Initial commit
This commit is contained in:
commit
0f66eee72b
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
dev.db
|
||||
.bundle
|
16
Gemfile
Normal file
16
Gemfile
Normal file
@ -0,0 +1,16 @@
|
||||
source 'https://rubygems.org'
|
||||
ruby '1.9.3'
|
||||
gem 'sinatra'
|
||||
gem 'activerecord'
|
||||
gem 'sinatra-activerecord'
|
||||
gem 'httparty'
|
||||
gem 'geocoder'
|
||||
gem 'algorithms'
|
||||
gem 'levenshtein-ffi', :require => 'levenshtein'
|
||||
|
||||
group :development, :test do
|
||||
gem 'sqlite3'
|
||||
end
|
||||
group :production, :staging do
|
||||
gem 'pg'
|
||||
end
|
65
Gemfile.lock
Normal file
65
Gemfile.lock
Normal file
@ -0,0 +1,65 @@
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
activemodel (4.0.2)
|
||||
activesupport (= 4.0.2)
|
||||
builder (~> 3.1.0)
|
||||
activerecord (4.0.2)
|
||||
activemodel (= 4.0.2)
|
||||
activerecord-deprecated_finders (~> 1.0.2)
|
||||
activesupport (= 4.0.2)
|
||||
arel (~> 4.0.0)
|
||||
activerecord-deprecated_finders (1.0.3)
|
||||
activesupport (4.0.2)
|
||||
i18n (~> 0.6, >= 0.6.4)
|
||||
minitest (~> 4.2)
|
||||
multi_json (~> 1.3)
|
||||
thread_safe (~> 0.1)
|
||||
tzinfo (~> 0.3.37)
|
||||
algorithms (0.6.1)
|
||||
arel (4.0.1)
|
||||
atomic (1.1.14)
|
||||
builder (3.1.4)
|
||||
ffi (1.1.5)
|
||||
geocoder (1.1.9)
|
||||
httparty (0.12.0)
|
||||
json (~> 1.8)
|
||||
multi_xml (>= 0.5.2)
|
||||
i18n (0.6.9)
|
||||
json (1.8.1)
|
||||
levenshtein-ffi (1.0.3)
|
||||
ffi
|
||||
ffi (~> 1.1.5)
|
||||
minitest (4.7.5)
|
||||
multi_json (1.8.4)
|
||||
multi_xml (0.5.5)
|
||||
pg (0.17.1)
|
||||
rack (1.5.2)
|
||||
rack-protection (1.5.1)
|
||||
rack
|
||||
sinatra (1.4.4)
|
||||
rack (~> 1.4)
|
||||
rack-protection (~> 1.4)
|
||||
tilt (~> 1.3, >= 1.3.4)
|
||||
sinatra-activerecord (1.2.3)
|
||||
activerecord (>= 3.0)
|
||||
sinatra (~> 1.0)
|
||||
sqlite3 (1.3.8)
|
||||
thread_safe (0.1.3)
|
||||
atomic
|
||||
tilt (1.4.1)
|
||||
tzinfo (0.3.38)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
activerecord
|
||||
algorithms
|
||||
geocoder
|
||||
httparty
|
||||
levenshtein-ffi
|
||||
pg
|
||||
sinatra
|
||||
sinatra-activerecord
|
||||
sqlite3
|
18
README.md
Normal file
18
README.md
Normal file
@ -0,0 +1,18 @@
|
||||
Clear Transit Server
|
||||
====================
|
||||
|
||||
What is this?
|
||||
-------------
|
||||
This is a server component of Clear Transit. An Android and Google Glass application for retrieving transit times from the NextBus Api
|
||||
|
||||
The Android client for this Heroku app is located at [Clear Transit](https://github.com/IamTheFij/ClearTransit")
|
||||
|
||||
I'm really not much of a Ruby dev, so this may be a little hacky. It's designed to run on Heroku using a Postgres DB.
|
||||
The initial database is built by running: `ruby ./build_agency_bounds.rb` or, if it fails midway, running `ruby ./continue_agency_bounds.rb`.
|
||||
|
||||
Heroku button
|
||||
-------------
|
||||
This buttons should install the server on Heroku. Should... no promises.
|
||||
|
||||
[![Deploy](https://www.herokucdn.com/deploy/button.png)](https://heroku.com/deploy?template=https://github.com/IamTheFij/ClearTransitServer)
|
||||
|
2
Rakefile
Normal file
2
Rakefile
Normal file
@ -0,0 +1,2 @@
|
||||
require './routes.rb'
|
||||
require 'sinatra/activerecord/rake'
|
18
app.json
Normal file
18
app.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "Clear Transit",
|
||||
"description": "Clear Transit web server",
|
||||
"keywords": [
|
||||
"transit",
|
||||
"Sinatra",
|
||||
"Ruby"
|
||||
],
|
||||
"website": "https://github.com/IamTheFij/ClearTransit-Web",
|
||||
"repository": "https://github.com/IamTheFij/ClearTransit-Web",
|
||||
"success_url": "/working",
|
||||
"scripts": {
|
||||
"postdeploy": "ruby ./build_agency_bounds.rb"
|
||||
},
|
||||
"addons": [
|
||||
"heroku-postgresql:hobby-dev"
|
||||
]
|
||||
}
|
48
build_agency_bounds.rb
Normal file
48
build_agency_bounds.rb
Normal file
@ -0,0 +1,48 @@
|
||||
require './environments.rb'
|
||||
require './models/active.rb'
|
||||
require './lib/nextbus.rb'
|
||||
require './lib/utils.rb'
|
||||
|
||||
agencies = {}
|
||||
|
||||
AgencyBound.all.each do |bound|
|
||||
bound.lat_min = nil
|
||||
bound.lat_max = nil
|
||||
bound.lon_min = nil
|
||||
bound.lon_max = nil
|
||||
agencies[bound.agency] = bound
|
||||
end
|
||||
|
||||
NextBus.agency_list.parsed_response['agency'].each do |agency|
|
||||
unless agencies.has_key?(agency['tag'])
|
||||
agencies[agency['tag']] = AgencyBound.new(
|
||||
agency: agency['tag'],
|
||||
lat_min: nil,
|
||||
lat_max: nil,
|
||||
lon_min: nil,
|
||||
lon_max: nil
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
agencies.each_value do |bound|
|
||||
routes = NextBus.routes(bound.agency).parsed_response['route']
|
||||
print "#{routes}\n"
|
||||
unless routes.nil?
|
||||
unless routes.kind_of?(Array)
|
||||
routes = [ routes ]
|
||||
end
|
||||
routes.each do |route|
|
||||
route_config = NextBus.route_config(bound.agency, route['tag']).parsed_response
|
||||
#print "Route Config:\n#{route_config}\n"
|
||||
route_config = route_config['route']
|
||||
print "Agency: #{bound.agency} Route: #{route['tag']} Bound Min: #{bound.lat_min}, Config Min #{route_config['latMin']}\n"
|
||||
bound.lat_min = min_val(bound.lat_min, route_config['latMin'].to_f)
|
||||
bound.lat_max = max_val(bound.lat_max, route_config['latMax'].to_f)
|
||||
bound.lon_min = min_val(bound.lon_min, route_config['lonMin'].to_f)
|
||||
bound.lon_max = max_val(bound.lon_max, route_config['lonMax'].to_f)
|
||||
end
|
||||
bound.save
|
||||
end
|
||||
end
|
||||
|
126
cleartransit.rb
Normal file
126
cleartransit.rb
Normal file
@ -0,0 +1,126 @@
|
||||
require 'sinatra'
|
||||
#require 'sinatra/activerecord'
|
||||
require 'json'
|
||||
require 'geocoder'
|
||||
require 'algorithms'
|
||||
require 'levenshtein'
|
||||
|
||||
require './environments.rb'
|
||||
require './models/active.rb'
|
||||
require './lib/nextbus.rb'
|
||||
require './lib/utils.rb'
|
||||
|
||||
# Uses bounds of the user and returns any agencies they are in the bounds of
|
||||
def get_contained_agencies(lat, lon)
|
||||
agencies = []
|
||||
|
||||
AgencyBound.all.each do |bound|
|
||||
if lat.between?(bound.lat_min, bound.lat_max) and lon.between?(bound.lon_min, bound.lon_max)
|
||||
agencies.push(bound.agency)
|
||||
end
|
||||
end
|
||||
|
||||
return agencies
|
||||
end
|
||||
|
||||
# Takes user input and agency and tries to find the most likely intended route
|
||||
def find_best_routes(agency, user_route)
|
||||
|
||||
# Remove Line from end of user_route
|
||||
user_route = user_route.downcase
|
||||
user_route_words = user_route.split
|
||||
if user_route_words.last == 'line'
|
||||
user_route_words.pop
|
||||
end
|
||||
user_route = user_route_words.join(' ')
|
||||
|
||||
# TODO: Remove before Prod
|
||||
routes = NextBus.routes(agency).parsed_response
|
||||
#routes = {
|
||||
# 'route' => [
|
||||
# {
|
||||
# 'title' => 'F - Market Warves',
|
||||
# 'tag' => 'F'
|
||||
# },
|
||||
# {
|
||||
# 'title' => 'P - ',
|
||||
# 'tag' => 'F'
|
||||
# }
|
||||
# ]
|
||||
#}
|
||||
|
||||
probable_routes = Containers::MinHeap.new
|
||||
|
||||
routes['route'].each do |route|
|
||||
dist = min_val(Levenshtein.distance(user_route, route['title'].downcase), Levenshtein.distance(user_route, route['tag'].downcase))
|
||||
route_match = RouteMatch.new(
|
||||
user_route: user_route,
|
||||
match_route: route['tag'],
|
||||
match_title: route['title'],
|
||||
agency: agency,
|
||||
# TODO: Depending on App implementation, default to false and set true or oposite
|
||||
accepted: false,
|
||||
distance: dist
|
||||
)
|
||||
probable_routes.push(dist, route_match)
|
||||
end
|
||||
|
||||
routes = []
|
||||
while not probable_routes.empty? and routes.length < 10
|
||||
routes.push(probable_routes.pop)
|
||||
end
|
||||
|
||||
return routes
|
||||
end
|
||||
|
||||
# Takes an agency, route, and lat-lon and returns nearest predictions
|
||||
def get_nearest_predictions(agency, route, lat, lon)
|
||||
current_location = [lat, lon]
|
||||
print current_location
|
||||
route_config = NextBus.route_config(agency, route).parsed_response
|
||||
|
||||
min_stops = Containers::MinHeap.new
|
||||
|
||||
route_config['route']['stop'].each do |stop|
|
||||
dist = Geocoder::Calculations.distance_between(current_location, [stop['lat'], stop['lon']])
|
||||
|
||||
min_stops.push(dist, stop)
|
||||
end
|
||||
|
||||
#stop_directions = build_direction_map(route_config)
|
||||
|
||||
stops = [], route_stops = []
|
||||
|
||||
while not min_stops.empty? and stops.length < 5
|
||||
stop = min_stops.pop
|
||||
# Build array out of the 5 closest stops
|
||||
stops.push(stop)
|
||||
# Push route stops for fetching predictions
|
||||
route_stops.push({:route => route, :stop => stop['tag']})
|
||||
end
|
||||
|
||||
min_stops.clear
|
||||
|
||||
prediction_multiple = NextBus.prediction_multiple(agency, route_stops).parsed_response
|
||||
|
||||
# TODO: Possibly adjust sort order here if these appear to be wrong
|
||||
|
||||
return prediction_multiple
|
||||
end
|
||||
|
||||
def build_direction_map(route_config)
|
||||
# TODO: DEPRECIATE
|
||||
stop_directions = {}
|
||||
|
||||
route_config['route']['direction'].each do |direction|
|
||||
direction['stop'].each do |stop|
|
||||
unless stop_directions[stop['tag']]
|
||||
stop_directions[stop['tag']] = []
|
||||
end
|
||||
stop_directions[stop['tag']].push(direction['name'])
|
||||
end
|
||||
end
|
||||
|
||||
return stop_directions
|
||||
end
|
||||
|
54
continue_agency_bounds.rb
Normal file
54
continue_agency_bounds.rb
Normal file
@ -0,0 +1,54 @@
|
||||
require './environments.rb'
|
||||
require './models/active.rb'
|
||||
require './lib/nextbus.rb'
|
||||
require './lib/utils.rb'
|
||||
|
||||
agencies = {}
|
||||
|
||||
AgencyBound.all.each do |bound|
|
||||
if bound.lat_max != nil
|
||||
agencies[bound.agency] = bound
|
||||
end
|
||||
end
|
||||
|
||||
NextBus.agency_list.parsed_response['agency'].each do |agency|
|
||||
if agencies.has_key?(agency['tag'])
|
||||
agencies.delete(agency['tag'])
|
||||
else
|
||||
agencies[agency['tag']] = AgencyBound.new(
|
||||
agency: agency['tag'],
|
||||
lat_min: nil,
|
||||
lat_max: nil,
|
||||
lon_min: nil,
|
||||
lon_max: nil
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
print "Agencies to get? #{agencies}"
|
||||
|
||||
if agencies.empty?
|
||||
print "No new agencies"
|
||||
end
|
||||
|
||||
agencies.each_value do |bound|
|
||||
routes = NextBus.routes(bound.agency).parsed_response['route']
|
||||
print "#{routes}\n"
|
||||
unless routes.nil?
|
||||
unless routes.kind_of?(Array)
|
||||
routes = [ routes ]
|
||||
end
|
||||
routes.each do |route|
|
||||
route_config = NextBus.route_config(bound.agency, route['tag']).parsed_response
|
||||
#print "Route Config:\n#{route_config}\n"
|
||||
route_config = route_config['route']
|
||||
print "Agency: #{bound.agency} Route: #{route['tag']} Bound Min: #{bound.lat_min}, Config Min #{route_config['latMin']}\n"
|
||||
bound.lat_min = min_val(bound.lat_min, route_config['latMin'].to_f)
|
||||
bound.lat_max = max_val(bound.lat_max, route_config['latMax'].to_f)
|
||||
bound.lon_min = min_val(bound.lon_min, route_config['lonMin'].to_f)
|
||||
bound.lon_max = max_val(bound.lon_max, route_config['lonMax'].to_f)
|
||||
end
|
||||
bound.save
|
||||
end
|
||||
end
|
||||
|
27
db/migrate/20140118012229_initial_db.rb
Normal file
27
db/migrate/20140118012229_initial_db.rb
Normal file
@ -0,0 +1,27 @@
|
||||
class InitialDb < ActiveRecord::Migration
|
||||
def up
|
||||
create_table :route_matches do |t|
|
||||
t.string :user_route
|
||||
t.string :match_route
|
||||
t.string :match_title
|
||||
t.integer :distance
|
||||
t.string :agency
|
||||
t.boolean :accepted
|
||||
t.timestamps
|
||||
end
|
||||
|
||||
create_table :agency_bounds do |t|
|
||||
t.string :agency
|
||||
t.float :lat_max
|
||||
t.float :lat_min
|
||||
t.float :lon_max
|
||||
t.float :lon_min
|
||||
t.timestamps
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
drop_table :route_matches
|
||||
drop_table :agency_bounds
|
||||
end
|
||||
end
|
36
db/schema.rb
Normal file
36
db/schema.rb
Normal file
@ -0,0 +1,36 @@
|
||||
# This file is auto-generated from the current state of the database. Instead
|
||||
# of editing this file, please use the migrations feature of Active Record to
|
||||
# incrementally modify your database, and then regenerate this schema definition.
|
||||
#
|
||||
# Note that this schema.rb definition is the authoritative source for your
|
||||
# database schema. If you need to create the application database on another
|
||||
# system, you should be using db:schema:load, not running all the migrations
|
||||
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
|
||||
# you'll amass, the slower it'll run and the greater likelihood for issues).
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 20140118012229) do
|
||||
|
||||
create_table "agency_bounds", force: true do |t|
|
||||
t.string "agency"
|
||||
t.float "lat_max"
|
||||
t.float "lat_min"
|
||||
t.float "lon_max"
|
||||
t.float "lon_min"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
end
|
||||
|
||||
create_table "route_matches", force: true do |t|
|
||||
t.string "user_route"
|
||||
t.string "match_route"
|
||||
t.string "match_title"
|
||||
t.integer "distance"
|
||||
t.string "agency"
|
||||
t.boolean "accepted"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
end
|
||||
|
||||
end
|
29
environments.rb
Normal file
29
environments.rb
Normal file
@ -0,0 +1,29 @@
|
||||
require 'cgi'
|
||||
require 'uri'
|
||||
require 'sinatra'
|
||||
require 'sinatra/activerecord'
|
||||
|
||||
configure :development do
|
||||
set :database, 'sqlite:///dev.db'
|
||||
set :show_exceptions, true
|
||||
end
|
||||
|
||||
configure :staging, :production do
|
||||
begin
|
||||
db = URI.parse(ENV["DATABASE_URL"])
|
||||
rescue URI::InvalidURIError
|
||||
raise "Invalid DATABASE_URL"
|
||||
end
|
||||
|
||||
ActiveRecord::Base.establish_connection(
|
||||
:adapter => db.scheme == 'postgres' ? 'postgresql' : db.scheme,
|
||||
:encoding => 'unicode',
|
||||
:pool => 5,
|
||||
:database => db.path[1..-1],
|
||||
:username => db.user,
|
||||
:password => db.password,
|
||||
:host => db.host,
|
||||
:port => db.port
|
||||
)
|
||||
end
|
||||
|
41
lib/nextbus.rb
Normal file
41
lib/nextbus.rb
Normal file
@ -0,0 +1,41 @@
|
||||
require 'httparty'
|
||||
|
||||
class NextBus
|
||||
include HTTParty
|
||||
|
||||
def self.get_command(command, query={})
|
||||
# Set the command
|
||||
query[:command] = command
|
||||
get('http://webservices.nextbus.com/service/publicJSONFeed', :query => query)
|
||||
end
|
||||
|
||||
def self.agency_list
|
||||
get_command('agencyList')
|
||||
end
|
||||
|
||||
def self.routes(agency)
|
||||
get_command('routeList', { :a => agency })
|
||||
end
|
||||
|
||||
def self.route_config(agency, route)
|
||||
get_command('routeConfig', { :a => agency, :r => route })
|
||||
end
|
||||
|
||||
def self.prediction(agency, route, stop, short_titles=true)
|
||||
get_command('predictions', { :a => agency, :r => route, :s => stop, :useShortTitles => short_titles })
|
||||
end
|
||||
|
||||
def self.prediction_multiple(agency, route_stops=[])
|
||||
endpoint = 'http://webservices.nextbus.com/service/publicJSONFeed'
|
||||
endpoint += '?command=predictionsForMultiStops'
|
||||
endpoint += '&a=' + agency
|
||||
route_stops.each do |route_stop|
|
||||
endpoint += '&stops=' + route_stop[:route] + '%7C' + route_stop[:stop]
|
||||
end
|
||||
|
||||
print endpoint
|
||||
|
||||
get(endpoint)
|
||||
end
|
||||
|
||||
end
|
35
lib/utils.rb
Normal file
35
lib/utils.rb
Normal file
@ -0,0 +1,35 @@
|
||||
def min_val(v1, v2)
|
||||
if v2 == nil
|
||||
return v1
|
||||
elsif v1 == nil
|
||||
return v2
|
||||
elsif v1 < v2
|
||||
return v1
|
||||
else
|
||||
return v2
|
||||
end
|
||||
end
|
||||
|
||||
def max_val(v1, v2)
|
||||
if v2 == nil
|
||||
return v1
|
||||
elsif v1 == nil
|
||||
return v2
|
||||
elsif v1 > v2
|
||||
return v1
|
||||
else
|
||||
return v2
|
||||
end
|
||||
end
|
||||
|
||||
def is_number?(object)
|
||||
true if Float(object) rescue false
|
||||
end
|
||||
|
||||
def to_f_nil(s)
|
||||
begin
|
||||
return Float(s)
|
||||
rescue
|
||||
return nil
|
||||
end
|
||||
end
|
5
models/active.rb
Normal file
5
models/active.rb
Normal file
@ -0,0 +1,5 @@
|
||||
# Require individual models here
|
||||
require 'active_record'
|
||||
|
||||
require './models/agency_bounds.rb'
|
||||
require './models/route_matches.rb'
|
8
models/agency_bounds.rb
Normal file
8
models/agency_bounds.rb
Normal file
@ -0,0 +1,8 @@
|
||||
# Table for storing boundries of given agencies to auto-detect
|
||||
class AgencyBound < ActiveRecord::Base
|
||||
validates :agency, :lat_max, :lat_min, :lon_max, :lon_min, presence: true
|
||||
# validates :lat_max, presence: true
|
||||
# validates :lat_min, presence: true
|
||||
# validates :lon_max, presence: true
|
||||
# validates :lon_min, presence: true
|
||||
end
|
9
models/route_matches.rb
Normal file
9
models/route_matches.rb
Normal file
@ -0,0 +1,9 @@
|
||||
# Table for storing the user input and levenshtein match
|
||||
# Will be used to assess accuracy and user acceptance
|
||||
class RouteMatch < ActiveRecord::Base
|
||||
validates :user_route, :match_route, :distance, presence: true
|
||||
# validates :match_route, presence: true
|
||||
# validates :distance, presence: true
|
||||
# TODO: Default value for accepted?
|
||||
end
|
||||
|
168
routes.rb
Normal file
168
routes.rb
Normal file
@ -0,0 +1,168 @@
|
||||
require 'sinatra'
|
||||
require 'sinatra/activerecord'
|
||||
require 'json'
|
||||
|
||||
require './cleartransit.rb'
|
||||
require './lib/nextbus.rb'
|
||||
|
||||
get '/' do
|
||||
# TODO: Provide link to download the app
|
||||
'Hello world! Go check out the repo: <a href="https://github.com/IamTheFij/CanHazMuni-Web">CanHazMuni-Web</a>'
|
||||
end
|
||||
|
||||
get '/working' do
|
||||
'Hello world! Go check out the repo: <a href="https://github.com/IamTheFij/CanHazMuni-Web">CanHazMuni-Web</a>'
|
||||
end
|
||||
|
||||
# List all agencies
|
||||
get '/agency' do
|
||||
status 200
|
||||
body(NextBus.agency_list.to_json)
|
||||
end
|
||||
|
||||
# List all routes in an agency
|
||||
get '/agency/:agency/route' do |agency|
|
||||
status 200
|
||||
body(NextBus.routes(agency).to_json)
|
||||
end
|
||||
|
||||
# List all stops in a route
|
||||
get '/agency/:agency/route/:route/stop' do |agency, route|
|
||||
status 200
|
||||
body(NextBus.route_config(agency, route).to_json)
|
||||
end
|
||||
|
||||
# Get predictions for a given stop
|
||||
get '/agency/:agency/route/:route/stop/:stop' do |agency, route, stop|
|
||||
status 200
|
||||
body(NextBus.prediction(agency, route, stop).to_json)
|
||||
end
|
||||
|
||||
# Get predictions for nearest stop on given agency and route
|
||||
get '/agency/:agency/route/:route/nearest' do |agency, route|
|
||||
# will match /agency/sf-muni/route/F/nearest?lat=37.804016399999995&lon=-122.40376609999998
|
||||
lat = to_f_nil(params[:lat])
|
||||
lon = to_f_nil(params[:lon])
|
||||
if params[:lat].nil? or lon.nil? or route.nil?
|
||||
status 404
|
||||
else
|
||||
status 200
|
||||
body(get_nearest_predictions(agency, route, lat, lon).to_json)
|
||||
end
|
||||
end
|
||||
|
||||
# Primary feature
|
||||
# Usine Lat, Lon, determine nearest agency, and stops and provide predictions
|
||||
=begin rdoc
|
||||
get '/icanhaz' do
|
||||
# will match /icanhaz?lat=37.804016399999995&lon=-122.40376609999998&route=F%20line
|
||||
|
||||
if params[:lat].nil? or params[:lon].nil? or params[:route].nil?
|
||||
status 404
|
||||
else
|
||||
status 200
|
||||
# TODO: Implement
|
||||
body({:thing1 => 'value'}.to_json)
|
||||
end
|
||||
end
|
||||
=end
|
||||
|
||||
# Usine Lat, Lon and given agency, and user route and provide predictions
|
||||
get '/icanhaz/:agency' do |agency|
|
||||
# will match /icanhaz/sf-muni?lat=37.804016399999995&lon=-122.40376609999998&route=F%20line
|
||||
lat = to_f_nil(params[:lat])
|
||||
lon = to_f_nil(params[:lon])
|
||||
if agency.nil? or lat.nil? or lon.nil? or params[:route].nil?
|
||||
body("Error: Post convert agency: #{agency} lat: #{lat} lon: #{lon} route: #{params[:route]}")
|
||||
status 404
|
||||
else
|
||||
status 200
|
||||
|
||||
# Use only the best route for now
|
||||
route = find_best_routes(agency, params[:route])[0]
|
||||
|
||||
body(get_nearest_predictions(agency, route[:tag], params[:lat], params[:lon]).to_json)
|
||||
end
|
||||
end
|
||||
|
||||
get '/icanhaz/agency/route' do
|
||||
# will match /icanhaz/agency/route?lat=37.804016399999995&lon=-122.40376609999998&route=F%20line
|
||||
lat = to_f_nil(params[:lat])
|
||||
lon = to_f_nil(params[:lon])
|
||||
if lat.nil? or lon.nil? or params[:route].nil?
|
||||
body("Error: Post convert lat: #{lat} lon: #{lon} route: #{params[:route]}")
|
||||
status 404
|
||||
else
|
||||
agencies = get_contained_agencies(lat, lon)
|
||||
|
||||
if agencies.empty?
|
||||
# TODO: Find better status code for something like this
|
||||
status 404
|
||||
|
||||
body("No service area found")
|
||||
else
|
||||
status 200
|
||||
|
||||
agency = agencies[0]
|
||||
user_route = params[:route];
|
||||
|
||||
# Get the most likely route in the agency
|
||||
# TODO: Match all the results returned to the RouteMatch class and insert all.
|
||||
# This will be super useful to provide a scroll list for the user to pick
|
||||
# alternate matches. The client can then mark which was actually matched.
|
||||
# When doing this, will probably want a unique "session" Id as well
|
||||
route_match = find_best_routes(agency, user_route)[0]
|
||||
route_match.save
|
||||
|
||||
body(route_match.to_json)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Usine given agency, and user route, guess the route
|
||||
get '/icanhaz/:agency/route' do |agency|
|
||||
# will match /icanhaz/sf-muni/route?route=F%20line
|
||||
if agency.nil? or params[:route].nil?
|
||||
status 404
|
||||
else
|
||||
status 200
|
||||
|
||||
user_route = params[:route];
|
||||
|
||||
# Get the most likely route in the agency
|
||||
# TODO: Match all the results returned to the RouteMatch class and insert all.
|
||||
# This will be super useful to provide a scroll list for the user to pick
|
||||
# alternate matches. The client can then mark which was actually matched.
|
||||
# When doing this, will probably want a unique "session" Id as well
|
||||
route_match = find_best_routes(agency, user_route)[0]
|
||||
route_match.save
|
||||
|
||||
body(route_match.to_json)
|
||||
end
|
||||
end
|
||||
|
||||
# Usine given agency, and actual route, get the predictions
|
||||
get '/icanhaz/:agency/route/:route' do |agency, route|
|
||||
# will match /icanhaz/sf-muni/route/F?lat=37.804016399999995&lon=-122.40376609999998
|
||||
# Optionally takes &match_id=123
|
||||
lat = to_f_nil(params[:lat])
|
||||
lon = to_f_nil(params[:lon])
|
||||
if agency.nil? or route.nil? or lat.nil? or lon.nil?
|
||||
body("Error: Post convert lat: #{lat} lon: #{lon} route: #{params[:route]}")
|
||||
status 404
|
||||
else
|
||||
status 200
|
||||
|
||||
# Get Id of databse tracked route match and indicate that it was accepted for predictions
|
||||
if not params[:match_id].nil?
|
||||
RouteMatch.update(params[:match_id], :accepted => true)
|
||||
end
|
||||
|
||||
body(get_nearest_predictions(agency, route, lat, lon).to_json)
|
||||
end
|
||||
end
|
||||
|
||||
get '/route_matches' do
|
||||
status 200
|
||||
body(RouteMatch.all.to_json)
|
||||
end
|
24
tags
Normal file
24
tags
Normal file
@ -0,0 +1,24 @@
|
||||
!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/
|
||||
!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/
|
||||
!_TAG_PROGRAM_AUTHOR Darren Hiebert /dhiebert@users.sourceforge.net/
|
||||
!_TAG_PROGRAM_NAME Exuberant Ctags //
|
||||
!_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/
|
||||
!_TAG_PROGRAM_VERSION 5.8 //
|
||||
AgencyBound models/agency_bounds.rb /^class AgencyBound < ActiveRecord::Base$/;" c
|
||||
InitialDb db/migrate/20140118012229_initial_db.rb /^class InitialDb < ActiveRecord::Migration$/;" c
|
||||
NextBus lib/nextbus.rb /^class NextBus$/;" c
|
||||
RouteMatch models/route_matches.rb /^class RouteMatch < ActiveRecord::Base$/;" c
|
||||
agency_list lib/nextbus.rb /^ def self.agency_list$/;" F class:NextBus
|
||||
build_direction_map canhazmuni.rb /^def build_direction_map(route_config)$/;" f
|
||||
down db/migrate/20140118012229_initial_db.rb /^ def down$/;" f class:InitialDb
|
||||
find_best_routes canhazmuni.rb /^def find_best_routes(agency, user_route)$/;" f
|
||||
get_command lib/nextbus.rb /^ def self.get_command(command, query={})$/;" F class:NextBus
|
||||
get_contained_agencies canhazmuni.rb /^def get_contained_agencies(lat, lon)$/;" f
|
||||
get_nearest_predictions canhazmuni.rb /^def get_nearest_predictions(agency, route, lat, lon)$/;" f
|
||||
max_val lib/utils.rb /^def max_val(v1, v2)$/;" f
|
||||
min_val lib/utils.rb /^def min_val(v1, v2)$/;" f
|
||||
prediction lib/nextbus.rb /^ def self.prediction(agency, route, stop, short_titles=true)$/;" F class:NextBus
|
||||
prediction_multiple lib/nextbus.rb /^ def self.prediction_multiple(agency, route_stops=[])$/;" F class:NextBus
|
||||
route_config lib/nextbus.rb /^ def self.route_config(agency, route)$/;" F class:NextBus
|
||||
routes lib/nextbus.rb /^ def self.routes(agency)$/;" F class:NextBus
|
||||
up db/migrate/20140118012229_initial_db.rb /^ def up$/;" f class:InitialDb
|
Loading…
Reference in New Issue
Block a user