gtfs 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md ADDED
@@ -0,0 +1,24 @@
1
+ ### GTFS Ruby
2
+
3
+ A Ruby wrapper for the General Transit Feed Specification
4
+
5
+ ### Getting started
6
+
7
+ Initialize a new GTFS source:
8
+
9
+ source = GTFS::Source.build(<URI or Path to GTFS zip file>)
10
+
11
+ Accessing GTFS data from the source:
12
+
13
+ source.agencies
14
+ source.stops
15
+ source.routes
16
+ source.trips
17
+ source.stop_times
18
+ source.calendar
19
+ source.calendar_dates
20
+ source.fare_attributes
21
+ source.fare_rules
22
+ source.shapes
23
+ source.frequencies
24
+ source.transfers
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env rake
2
+ require 'rubygems'
3
+ require 'rspec/core/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new do |t|
6
+ t.pattern = "./spec/**/*_spec.rb"
7
+ end
@@ -0,0 +1,15 @@
1
+ module GTFS
2
+ class Agency
3
+ include GTFS::Model
4
+
5
+ has_required_attrs :name, :url, :timezone
6
+ has_optional_attrs :id, :lang, :phone, :fare_url
7
+ attr_accessor *attrs
8
+
9
+ column_prefix :agency_
10
+
11
+ def self.parse_agencies(data)
12
+ return parse_models(data)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,12 @@
1
+ module GTFS
2
+ class Calendar
3
+ include GTFS::Model
4
+
5
+ has_required_attrs :service_id, :monday, :tuesday, :wednesday, :thursday, :friday, :saturday, :sunday, :start_date, :end_date
6
+ attr_accessor *attrs
7
+
8
+ def self.parse_calendars(data)
9
+ return parse_models(data)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ module GTFS
2
+ class CalendarDate
3
+ include GTFS::Model
4
+
5
+ has_required_attrs :service_id, :date, :exception_type
6
+ attr_accessor *attrs
7
+
8
+ def self.parse_calendar_dates(data)
9
+ return parse_models(data)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,4 @@
1
+ module GTFS
2
+ class InvalidSourceException < Exception
3
+ end
4
+ end
@@ -0,0 +1,10 @@
1
+ module GTFS
2
+ class LocalSource < Source
3
+
4
+ def load_archive(source_path)
5
+ extract_to_cache(source_path)
6
+ rescue Exception => e
7
+ raise InvalidSourceException.new(e.message)
8
+ end
9
+ end
10
+ end
data/lib/gtfs/model.rb ADDED
@@ -0,0 +1,77 @@
1
+ require 'CSV'
2
+
3
+ module GTFS
4
+ module Model
5
+ def self.included(base)
6
+ base.extend ClassMethods
7
+
8
+ base.class_variable_set('@@prefix', '')
9
+ base.class_variable_set('@@optional_attrs', [])
10
+ base.class_variable_set('@@required_attrs', [])
11
+
12
+ def valid?
13
+ !self.class.required_attrs.any?{|f| self.send(f.to_sym).nil?}
14
+ end
15
+
16
+ def initialize(attrs)
17
+ attrs.each do |key, val|
18
+ instance_variable_set("@#{key}", val)
19
+ end
20
+ end
21
+ end
22
+
23
+ module ClassMethods
24
+
25
+ #####################################
26
+ # Getters for class variables
27
+ #####################################
28
+
29
+ def prefix
30
+ self.class_variable_get('@@prefix')
31
+ end
32
+
33
+ def optional_attrs
34
+ self.class_variable_get('@@optional_attrs')
35
+ end
36
+
37
+ def required_attrs
38
+ self.class_variable_get('@@required_attrs')
39
+ end
40
+
41
+ def attrs
42
+ required_attrs + optional_attrs
43
+ end
44
+
45
+ #####################################
46
+ # Helper methods for setting up class variables
47
+ #####################################
48
+
49
+ def has_required_attrs(*attrs)
50
+ self.class_variable_set('@@required_attrs', attrs)
51
+ end
52
+
53
+ def has_optional_attrs(*attrs)
54
+ self.class_variable_set('@@optional_attrs', attrs)
55
+ end
56
+
57
+ def column_prefix(prefix)
58
+ self.class_variable_set('@@prefix', prefix)
59
+ end
60
+
61
+ def parse_models(data)
62
+ return [] if data.nil? || data.empty?
63
+
64
+ models = []
65
+ CSV.parse(data, :headers => true) do |row|
66
+ attr_hash = {}
67
+ row.to_hash.each do |key, val|
68
+ attr_hash[key.gsub(/^#{prefix}/, '')] = val
69
+ end
70
+ model = self.new(attr_hash)
71
+ models << model if model.valid?
72
+ end
73
+ models
74
+ end
75
+ end
76
+ end
77
+ end
data/lib/gtfs/route.rb ADDED
@@ -0,0 +1,15 @@
1
+ module GTFS
2
+ class Route
3
+ include GTFS::Model
4
+
5
+ has_required_attrs :id, :short_name, :long_name, :type
6
+ has_optional_attrs :agency_id, :desc, :url, :color, :text_color
7
+ attr_accessor *attrs
8
+
9
+ column_prefix :route_
10
+
11
+ def self.parse_routes(data)
12
+ return parse_models(data)
13
+ end
14
+ end
15
+ end
data/lib/gtfs/shape.rb ADDED
@@ -0,0 +1,15 @@
1
+ module GTFS
2
+ class Shape
3
+ include GTFS::Model
4
+
5
+ has_required_attrs :id, :pt_lat, :pt_lon, :pt_sequence
6
+ has_optional_attrs :dist_traveled
7
+ attr_accessor *attrs
8
+
9
+ column_prefix :shape_
10
+
11
+ def self.parse_shapes(data)
12
+ return parse_models(data)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,114 @@
1
+ require 'tmpdir'
2
+ require 'fileutils'
3
+ require 'zip/zip'
4
+
5
+ module GTFS
6
+ class Source
7
+
8
+ REQUIRED_SOURCE_FILES = %w{agency.txt stops.txt routes.txt trips.txt stop_times.txt calendar.txt}
9
+ OPTIONAL_SOURCE_FILES = %w{calendar_dates.txt fare_attributes.txt fare_rules.txt shapes.txt frequencies.txt transfers.txt}
10
+ SOURCE_FILES = REQUIRED_SOURCE_FILES + OPTIONAL_SOURCE_FILES
11
+
12
+ attr_accessor :source, :archive
13
+
14
+ def initialize(source)
15
+ raise 'Source cannot be nil' if source.nil?
16
+
17
+ @tmp_dir = Dir.mktmpdir
18
+ ObjectSpace.define_finalizer(self, self.class.finalize(@tmp_dir))
19
+
20
+ @source = source
21
+ load_archive(@source)
22
+
23
+ raise InvalidSourceException.new('Missing required source files') if missing_sources?
24
+ end
25
+
26
+ def self.finalize(directory)
27
+ proc {FileUtils.rm_rf(directory)}
28
+ end
29
+
30
+ def extract_to_cache(source_path)
31
+ Zip::ZipFile.open(source_path) do |zip|
32
+ zip.entries.each do |entry|
33
+ zip.extract(entry.name, File.join(@tmp_dir, '/', entry.name))
34
+ end
35
+ end
36
+ end
37
+
38
+ def load_archive(source)
39
+ raise 'Cannot directly instantiate base GTFS::Source'
40
+ end
41
+
42
+ def self.build(data_root)
43
+ if data_root.match(/http|www/)
44
+ URLSource.new(data_root)
45
+ else
46
+ LocalSource.new(data_root)
47
+ end
48
+ end
49
+
50
+ def entries
51
+ Dir.entries(@tmp_dir)
52
+ end
53
+
54
+ def missing_sources?
55
+ return true if @source.nil?
56
+
57
+ REQUIRED_SOURCE_FILES.each do |rf|
58
+ return true if !entries.include?(rf)
59
+ end
60
+ false
61
+ end
62
+
63
+ def agencies
64
+ open(File.join(@tmp_dir, '/', 'agency.txt')) do |f|
65
+ @agencies ||= Agency.parse_agencies(f.read)
66
+ end
67
+ @agencies
68
+ end
69
+
70
+ def stops
71
+ open(File.join(@tmp_dir, '/', 'stops.txt')) do |f|
72
+ @stops ||= Stop.parse_stops(f.read)
73
+ end
74
+ @stops
75
+ end
76
+
77
+ def calendars
78
+ open(File.join(@tmp_dir, '/', 'calendar.txt')) do |f|
79
+ @calendars ||= Calendar.parse_calendars(f.read)
80
+ end
81
+ @calendars
82
+ end
83
+
84
+ def routes
85
+ open(File.join(@tmp_dir, '/', 'routes.txt')) do |f|
86
+ @routes ||= Route.parse_routes(f.read)
87
+ end
88
+ @routes
89
+ end
90
+
91
+ # TODO: huge, isn't practical to parse all at once
92
+ def shapes
93
+ open(File.join(@tmp_dir, '/', 'shapes.txt')) do |f|
94
+ @shapes ||= Shape.parse_shapes(f.read)
95
+ end
96
+ @shapes
97
+ end
98
+
99
+ def trips
100
+ open(File.join(@tmp_dir, '/', 'trips.txt')) do |f|
101
+ @trips ||= Trip.parse_trips(f.read)
102
+ end
103
+ @trips
104
+ end
105
+
106
+ # TODO: huge, isn't practical to parse all at once
107
+ def stop_times
108
+ open(File.join(@tmp_dir, '/', 'stop_times.txt')) do |f|
109
+ @stop_times ||= StopTime.parse_stop_times(f.read)
110
+ end
111
+ @stop_times
112
+ end
113
+ end
114
+ end
data/lib/gtfs/stop.rb ADDED
@@ -0,0 +1,18 @@
1
+ module GTFS
2
+ class Stop
3
+ include GTFS::Model
4
+
5
+ has_required_attrs :id, :name, :lat, :lon
6
+ has_optional_attrs :code, :desc, :zone_id, :url, :location_type, :parent_station, :timezone
7
+ column_prefix :stop_
8
+ attr_accessor *attrs
9
+
10
+ LOCATION_TYPE_STOP = 0
11
+ LOCATION_TYPE_STATION = 1
12
+
13
+ def self.parse_stops(data)
14
+ return parse_models(data)
15
+ end
16
+ end
17
+ end
18
+
@@ -0,0 +1,13 @@
1
+ module GTFS
2
+ class StopTime
3
+ include GTFS::Model
4
+
5
+ has_required_attrs :trip_id, :arrival_time, :departure_time, :stop_id, :stop_sequence
6
+ has_optional_attrs :stop_headsign, :pickup_type, :drop_off_type, :shape_dist_traveled
7
+ attr_accessor *attrs
8
+
9
+ def self.parse_stop_times(data)
10
+ return parse_models(data)
11
+ end
12
+ end
13
+ end
data/lib/gtfs/trip.rb ADDED
@@ -0,0 +1,15 @@
1
+ module GTFS
2
+ class Trip
3
+ include GTFS::Model
4
+
5
+ has_required_attrs :route_id, :service_id, :id
6
+ has_optional_attrs :headsign, :short_name, :direction_id, :block_id, :shape_id
7
+ attr_accessor *attrs
8
+
9
+ column_prefix :trip_
10
+
11
+ def self.parse_trips(data)
12
+ return parse_models(data)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,22 @@
1
+ require 'net/http'
2
+ require 'URI'
3
+
4
+ module GTFS
5
+ class URLSource < Source
6
+
7
+ def load_archive(source_url)
8
+ Dir.mktmpdir do |tmp|
9
+ file_name = File.join(tmp, "/gtfs_temp_#{Time.now}.zip")
10
+ uri = URI.parse(source_url)
11
+ response = Net::HTTP.get_response(uri)
12
+ open(file_name, 'wb') do |file|
13
+ file.write response.body
14
+ end
15
+ extract_to_cache(file_name)
16
+ end
17
+ rescue Exception => e
18
+ raise InvalidSourceException.new(e.message)
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,4 @@
1
+ module GTFS
2
+ VERSION = '0.1.0'
3
+ end
4
+
data/lib/gtfs.rb ADDED
@@ -0,0 +1,14 @@
1
+ require 'gtfs/version'
2
+ require 'gtfs/model'
3
+ require 'gtfs/agency'
4
+ require 'gtfs/calendar'
5
+ require 'gtfs/calendar_date'
6
+ require 'gtfs/source'
7
+ require 'gtfs/url_source'
8
+ require 'gtfs/local_source'
9
+ require 'gtfs/route'
10
+ require 'gtfs/shape'
11
+ require 'gtfs/stop'
12
+ require 'gtfs/stop_time'
13
+ require 'gtfs/trip'
14
+ require 'gtfs/custom_exceptions'
@@ -0,0 +1,70 @@
1
+ ---
2
+ - !ruby/struct:VCR::HTTPInteraction
3
+ request: !ruby/struct:VCR::Request
4
+ method: :get
5
+ uri: http://www.edschmalzle.com:80/gtfs.zip
6
+ body: !!null
7
+ headers: !!null
8
+ response: !ruby/struct:VCR::Response
9
+ status: !ruby/struct:VCR::ResponseStatus
10
+ code: 404
11
+ message: Not Found
12
+ headers:
13
+ date:
14
+ - Wed, 18 Jan 2012 05:04:53 GMT
15
+ server:
16
+ - Apache
17
+ vary:
18
+ - Cookie,Accept-Encoding
19
+ x-pingback:
20
+ - http://www.edschmalzle.com/xmlrpc.php
21
+ expires:
22
+ - Wed, 11 Jan 1984 05:00:00 GMT
23
+ cache-control:
24
+ - no-cache, must-revalidate, max-age=0
25
+ pragma:
26
+ - no-cache
27
+ last-modified:
28
+ - Wed, 18 Jan 2012 05:04:54 GMT
29
+ transfer-encoding:
30
+ - chunked
31
+ content-type:
32
+ - text/html; charset=UTF-8
33
+ body: ! "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\r\n<html
34
+ xmlns=\"http://www.w3.org/1999/xhtml\" dir=\"ltr\" lang=\"en-US\">\r\n<head
35
+ profile=\"http://gmpg.org/xfn/11\">\r\n<meta http-equiv=\"Content-Type\" content=\"text/html;
36
+ charset=UTF-8\" />\r\n<title>Ed Schmalzle &raquo; Page not found</title>\r\n<link
37
+ rel=\"stylesheet\" href=\"http://www.edschmalzle.com/wp-content/themes/shallowgrunge/shallowgrunge/style.css\"
38
+ type=\"text/css\" media=\"screen\" />\r\n<link rel=\"alternate\" type=\"application/rss+xml\"
39
+ title=\"Ed Schmalzle RSS Feed\" href=\"http://www.edschmalzle.com/feed/\" />\r\n<link
40
+ rel=\"pingback\" href=\"http://www.edschmalzle.com/xmlrpc.php\" />\r\n<script
41
+ type='text/javascript' src='http://www.edschmalzle.com/wp-includes/js/jquery/jquery.js?ver=1.7.1'></script>\n<script
42
+ type='text/javascript' src='http://www.edschmalzle.com/wp-content/plugins/google-analyticator/external-tracking.min.js?ver=6.2'></script>\n<link
43
+ rel=\"EditURI\" type=\"application/rsd+xml\" title=\"RSD\" href=\"http://www.edschmalzle.com/xmlrpc.php?rsd\"
44
+ />\n<link rel=\"wlwmanifest\" type=\"application/wlwmanifest+xml\" href=\"http://www.edschmalzle.com/wp-includes/wlwmanifest.xml\"
45
+ /> \n<meta name=\"generator\" content=\"WordPress 3.3.1\" />\n<!-- Google Analytics
46
+ Tracking by Google Analyticator 6.2: http://ronaldheft.com/code/analyticator/
47
+ -->\n<script type=\"text/javascript\">\n\tvar analyticsFileTypes = [''];\n\tvar
48
+ analyticsEventTracking = 'enabled';\n</script>\n<script type=\"text/javascript\">\n\tvar
49
+ _gaq = _gaq || [];\n\t_gaq.push(['_setAccount', 'UA-378745-4']);\n\t_gaq.push(['_trackPageview']);\n\t_gaq.push(['_trackPageLoadTime']);\n\n\t(function()
50
+ {\n\t\tvar ga = document.createElement('script'); ga.type = 'text/javascript';
51
+ ga.async = true;\n\t\tga.src = ('https:' == document.location.protocol ? 'https://ssl'
52
+ : 'http://www') + '.google-analytics.com/ga.js';\n\t\tvar s = document.getElementsByTagName('script')[0];
53
+ s.parentNode.insertBefore(ga, s);\n\t})();\n</script>\n</head>\r\n<body>\r\n<div
54
+ id=\"wrapper\">\r\n<div id=\"wrapper2\">\r\n\r\n<div id=\"header\">\r\n\t<div
55
+ id=\"logo\">\r\n\t\t<h1><a href=\"http://www.edschmalzle.com/\">Ed Schmalzle</a></h1>\r\n\t\t<p></p>\r\n\t</div>\r\n</div>\r\n<!--
56
+ end #header -->\r\n<div id=\"menu\">\r\n\t<ul>\r\n\t\t<li class=\"page_item\"><a
57
+ href=\"http://www.edschmalzle.com/\">Blog</a></li>\r\n\t\t<li class=\"page_item
58
+ page-item-60\"><a href=\"http://www.edschmalzle.com/projects/\">Projects</a></li>\n<li
59
+ class=\"page_item page-item-5\"><a href=\"http://www.edschmalzle.com/resume/\">Resume</a></li>\n<li
60
+ class=\"page_item page-item-6\"><a href=\"http://www.edschmalzle.com/contact/\">Contact</a></li>\n<li
61
+ class=\"page_item page-item-75\"><a href=\"http://www.edschmalzle.com/archives/\">Archives</a></li>\n\t\t<li
62
+ class=\"page_item\"><a href=\"http://www.edschmalzle.com/feed/\">RSS</a></li>\r\n\t</ul>\r\n</div>\r\n<!--
63
+ end #menu -->\r\n</div>\r\n<hr />\r\n\r\n<div id=\"page\">\r\n\t<div id=\"content\"
64
+ class=\"narrowcolumn\">\r\n\r\n\t\t<h2 class=\"center\">Error 404 - Not Found</h2>\r\n\r\n\t</div>\r\n\r\n<div
65
+ id=\"sidebar\">\r\n\t<ul>\r\n\t</ul>\r\n</div>\r\n<!-- end #sidebar -->\r\n\r\n<div
66
+ style=\"clear: both;\">&nbsp;</div>\r\n</div>\r\n<!-- end #page -->\r\n<hr />\r\n</div>\r\n</div>\r\n<!--
67
+ end #footer -->\r\n<div id=\"footer\">\r\n\t<div>\r\n\t\t<p>Copyright (c) 2008\r\n\t\t\tEd
68
+ Schmalzle\t\t\tAll rights reserved. Design by <a href=\"http://www.freewpthemes.net/\">Free
69
+ WordPress Themes</a> &nbsp;&bull;&nbsp;\r\n\t\t\tPowered by <a href=\"http://wordpress.org/\">WordPress</a></p>\r\n\t</div>\r\n</div>\r\n</body></html>"
70
+ http_version: '1.1'
@@ -0,0 +1,127 @@
1
+ ---
2
+ - !ruby/struct:VCR::HTTPInteraction
3
+ request: !ruby/struct:VCR::Request
4
+ method: :get
5
+ uri: http://dl.dropbox.com:80/u/416235/work/valid_gtfs.zip
6
+ body: !!null
7
+ headers: !!null
8
+ response: !ruby/struct:VCR::Response
9
+ status: !ruby/struct:VCR::ResponseStatus
10
+ code: 200
11
+ message: OK
12
+ headers:
13
+ server:
14
+ - nginx/1.0.14
15
+ date:
16
+ - Fri, 13 Apr 2012 21:52:30 GMT
17
+ content-type:
18
+ - application/zip
19
+ connection:
20
+ - keep-alive
21
+ content-length:
22
+ - '4147'
23
+ x-robots-tag:
24
+ - noindex,nofollow
25
+ accept-ranges:
26
+ - bytes
27
+ etag:
28
+ - 1380046134n
29
+ pragma:
30
+ - public
31
+ cache-control:
32
+ - max-age=0
33
+ body: !binary |-
34
+ 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
126
+ AJENAAAAAA==
127
+ http_version: '1.1'
Binary file
Binary file
@@ -0,0 +1,14 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe GTFS::Agency do
4
+ describe 'Agency.parse_agencies' do
5
+ let(:header_line) {"agency_id,agency_name,agency_url,agency_timezone,agency_lang,agency_phone\n"}
6
+ let(:invalid_header_line) {"agency_id,agency_url,agency_timezone,agency_lang,agency_phone\n"}
7
+ let(:valid_line) {"1,Maryland Transit Administration,http://www.mta.maryland.gov,America/New_York,en,410-539-5000\n"}
8
+ let(:invalid_line) {"1,,http://www.mta.maryland.gov,America/New_York,en,410-539-5000\n"}
9
+
10
+ subject {GTFS::Agency.parse_agencies(source_text)}
11
+
12
+ include_examples 'models'
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe GTFS::CalendarDate do
4
+ describe 'CalendarDate.parse_calendar_dates' do
5
+ let(:header_line) {"service_id,date,exception_type\n"}
6
+ let(:invalid_header_line) {",date,\n"}
7
+ let(:valid_line) {"3,20110905,1\n"}
8
+ let(:invalid_line) {"3,,1\n"}
9
+
10
+ subject {GTFS::CalendarDate.parse_calendar_dates(source_text)}
11
+
12
+ include_examples 'models'
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe GTFS::Calendar do
4
+ describe 'Calendar.parse_calendars' do
5
+ let(:header_line) {"service_id,monday,tuesday,wednesday,thursday,friday,saturday,sunday,start_date,end_date\n"}
6
+ let(:invalid_header_line) {"service_id,,tuesday,,thursday,friday,,sunday,start_date,end_date\n"}
7
+ let(:valid_line) {"1,1,1,1,1,1,0,0,20110828,20120204\n"}
8
+ let(:invalid_line) {"1,,1,,1,,0,,,20120204\n"}
9
+
10
+ subject {GTFS::Calendar.parse_calendars(source_text)}
11
+
12
+ include_examples 'models'
13
+ end
14
+ end
@@ -0,0 +1,25 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe GTFS::LocalSource do
4
+ describe '#new' do
5
+ subject {lambda{GTFS::LocalSource.new(source_path)}}
6
+
7
+ context 'with a local source path that is invalid' do
8
+ let(:source_path) {File.expand_path(File.dirname(__FILE__) + '/../fixtures/not_here.zip')}
9
+
10
+ it {should raise_error(GTFS::InvalidSourceException)}
11
+ end
12
+
13
+ context 'with a local source path to a zip w/o required files' do
14
+ let(:source_path) {File.expand_path(File.dirname(__FILE__) + '/../fixtures/missing_files_gtfs.zip')}
15
+
16
+ it {should raise_error(GTFS::InvalidSourceException)}
17
+ end
18
+
19
+ context 'with a local source path to a valid source zip' do
20
+ let(:source_path) {File.expand_path(File.dirname(__FILE__) + '/../fixtures/valid_gtfs.zip')}
21
+
22
+ it {should_not raise_error(GTFS::InvalidSourceException)}
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,14 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe GTFS::Route do
4
+ describe 'Route.parse_routes' do
5
+ let(:header_line) {"route_id,agency_id,route_short_name,route_long_name,route_desc,route_type,route_url,route_color,route_text_color\n"}
6
+ let(:invalid_header_line) {",agency_id,,route_long_name,,route_type,,route_color,\n"}
7
+ let(:valid_line) {"4679,1,001,SINAI - FORT McHENRY,,3,,0000FF,FFFFFF\n"}
8
+ let(:invalid_line) {",1,,,,3,,,FFFFFF\n"}
9
+
10
+ subject {GTFS::Route.parse_routes(source_text)}
11
+
12
+ include_examples 'models'
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe GTFS::Shape do
4
+ describe 'Shape.parse_shapes' do
5
+ let(:header_line) {"shape_id,shape_pt_lat,shape_pt_lon,shape_pt_sequence,shape_dist_traveled\n"}
6
+ let(:invalid_header_line) {",,,shape_pt_sequence,shape_dist_traveled\n"}
7
+ let(:valid_line) {"59135,39.354286,-76.662453,19,0.8136\n"}
8
+ let(:invalid_line) {",39.354286,,,0.8136\n"}
9
+
10
+ subject {GTFS::Shape.parse_shapes(source_text)}
11
+
12
+ include_examples 'models'
13
+ end
14
+ end
@@ -0,0 +1,65 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe GTFS::Source do
4
+ let(:valid_local_source) {File.expand_path(File.dirname(__FILE__) + '/../fixtures/valid_gtfs.zip')}
5
+ let(:source_missing_required_files) {File.expand_path(File.dirname(__FILE__) + '/../fixtures/missing_files.zip')}
6
+
7
+ describe '#build' do
8
+ subject {GTFS::Source.build(data_source)}
9
+
10
+ before do
11
+ GTFS::URLSource.stub(:new).and_return('URLSource')
12
+ GTFS::LocalSource.stub(:new).and_return('LocalSource')
13
+ end
14
+
15
+ context 'with a url as a data root' do
16
+ let(:data_source) {'http://www.edschmalzle.com/gtfs.zip'}
17
+
18
+ it {should == 'URLSource'}
19
+ end
20
+
21
+ context 'with a file path as a data root' do
22
+ let(:data_source) {valid_local_source}
23
+
24
+ it {should == 'LocalSource'}
25
+ end
26
+ end
27
+
28
+ describe '#build' do
29
+ context 'when the source lacks a required file' do
30
+ it 'should raise an exception if the source is missing a file' do
31
+ lambda {GTFS::Source.build(source_missing_required_fields)}.should raise_exception
32
+ end
33
+ end
34
+ end
35
+
36
+ describe '#new(source)' do
37
+ it 'should not allow a base GTFS::Source to be initialized' do
38
+ lambda {GTFS::Source.new(valid_local_source)}.should raise_exception
39
+ end
40
+ end
41
+
42
+ describe '#agencies' do
43
+ subject {source.agencies}
44
+
45
+ context 'when the source has agencies' do
46
+ let(:source) {GTFS::Source.build(valid_local_source)}
47
+
48
+ it {should_not be_empty}
49
+ its(:first) {should be_an_instance_of(GTFS::Agency)}
50
+ end
51
+
52
+ end
53
+
54
+ describe '#stops' do
55
+ end
56
+
57
+ describe '#routes' do
58
+ end
59
+
60
+ describe '#trips' do
61
+ end
62
+
63
+ describe '#stop_times' do
64
+ end
65
+ end
@@ -0,0 +1,15 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe GTFS::Stop do
4
+ describe 'Trip.parse_stops' do
5
+ let(:header_line) {"stop_id,stop_code,stop_name,stop_lat,stop_lon,zone_id,stop_url,location_type,parent_station\n"}
6
+ let(:invalid_header_line) {"stop_lon, zone_id, stop_url, location_type\n"}
7
+ let(:valid_line) {"3,C093,LANIER & SINAI HOSPITAL,39.351145,-76.663113,,,,\n"}
8
+ let(:invalid_line) {"3,,,,-76.663113,,,,\n"}
9
+
10
+ subject {GTFS::Stop.parse_stops(source_text)}
11
+
12
+ include_examples 'models'
13
+ end
14
+ end
15
+
@@ -0,0 +1,15 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe GTFS::StopTime do
4
+ describe 'StopTime.parse_stop_times' do
5
+ let(:header_line) {"trip_id,arrival_time,departure_time,stop_id,stop_sequence,stop_headsign,pickup_type,drop_off_type,shape_dist_traveled\n"}
6
+ let(:invalid_header_line) {",arrival_time,,stop_id,,stop_headsign,,drop_off_type,\n"}
7
+ let(:valid_line) {"982385,4:34:00,4:34:00,277,1,,0,0,\n"}
8
+ let(:invalid_line) {",,4:34:00,,1,,,0,\n"}
9
+
10
+ subject {GTFS::StopTime.parse_stop_times(source_text)}
11
+
12
+ include_examples 'models'
13
+ end
14
+ end
15
+
@@ -0,0 +1,16 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe GTFS::Trip do
4
+ describe 'Trip.parse_trips' do
5
+ let(:header_line) {"route_id,service_id,trip_id,trip_headsign,direction_id,block_id,shape_id\n"}
6
+ let(:invalid_header_line) {",,,,direction_id,block_id,shape_id\n"}
7
+ let(:valid_line) {"4679,1,982394,1 FT McHENRY,0,189021,59135\n"}
8
+ let(:invalid_line) {",1,,1 FT McHENRY,,189021,\n"}
9
+
10
+ subject {GTFS::Trip.parse_trips(source_text)}
11
+
12
+ include_examples 'models'
13
+ end
14
+ end
15
+
16
+
@@ -0,0 +1,21 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe GTFS::URLSource do
4
+ context 'with a URI to a valid source zip' do
5
+ let(:source_path) {'http://dl.dropbox.com/u/416235/work/valid_gtfs.zip'}
6
+ it 'should create a new source successfully' do
7
+ VCR.use_cassette('valid_gtfs_uri') do
8
+ lambda {GTFS::URLSource.new(source_path)}.should_not raise_error(GTFS::InvalidSourceException)
9
+ end
10
+ end
11
+ end
12
+
13
+ context 'with a non-existent URI' do
14
+ let(:source_path) {'http://www.edschmalzle.com/gtfs.zip'}
15
+ it 'should raise an exception' do
16
+ VCR.use_cassette('invalid_gtfs_uri') do
17
+ lambda {GTFS::URLSource.new(source_path)}.should raise_error(GTFS::InvalidSourceException)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,22 @@
1
+ require 'simplecov'
2
+ SimpleCov.start
3
+
4
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+
7
+ require 'bundler/setup'
8
+ require 'rspec'
9
+ require 'vcr'
10
+ require 'ruby-debug'
11
+ require 'gtfs'
12
+
13
+ require File.expand_path(File.dirname(__FILE__) + '/support/model_shared_examples')
14
+
15
+ RSpec.configure do |config|
16
+ # Configure you some RSpec
17
+ end
18
+
19
+ VCR.config do |c|
20
+ c.cassette_library_dir = File.join(File.dirname(__FILE__), '/fixtures/cassettes')
21
+ c.stub_with :fakeweb
22
+ end
@@ -0,0 +1,31 @@
1
+ shared_examples 'models' do |collection_class|
2
+ context 'with a nil source' do
3
+ let(:source_text) {nil}
4
+ it {should == []}
5
+ end
6
+
7
+ context 'with an empty source' do
8
+ let(:source_text) {''}
9
+ it {should == []}
10
+ end
11
+
12
+ context 'with a source w/ only headers' do
13
+ let(:source_text) {header_line}
14
+ it {should == []}
15
+ end
16
+
17
+ context 'with a valid row of data' do
18
+ let(:source_text) {header_line + valid_line}
19
+ its(:size) {should == 1}
20
+ end
21
+
22
+ context 'with multiple valid rows of data' do
23
+ let(:source_text) {header_line + valid_line + valid_line}
24
+ its(:size) {should == 2}
25
+ end
26
+
27
+ context 'with 1 invalid and 1 valid row of data' do
28
+ let(:source_text) {header_line + valid_line + invalid_line}
29
+ its(:size) {should == 1}
30
+ end
31
+ end
metadata ADDED
@@ -0,0 +1,208 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gtfs
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - nerdEd
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-07-03 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: multi_json
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rubyzip
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: rspec
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: 2.0.0
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: 2.0.0
78
+ - !ruby/object:Gem::Dependency
79
+ name: simplecov
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: ruby-debug19
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ - !ruby/object:Gem::Dependency
111
+ name: vcr
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ - !ruby/object:Gem::Dependency
127
+ name: fakeweb
128
+ requirement: !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ! '>='
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ type: :development
135
+ prerelease: false
136
+ version_requirements: !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ! '>='
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
142
+ description: gtfs reads GTFS data from a google-compliant Zip bundle and returns an
143
+ object representing the CSV data inside
144
+ email:
145
+ - nerdEd
146
+ executables: []
147
+ extensions: []
148
+ extra_rdoc_files: []
149
+ files:
150
+ - Rakefile
151
+ - lib/gtfs/agency.rb
152
+ - lib/gtfs/calendar.rb
153
+ - lib/gtfs/calendar_date.rb
154
+ - lib/gtfs/custom_exceptions.rb
155
+ - lib/gtfs/local_source.rb
156
+ - lib/gtfs/model.rb
157
+ - lib/gtfs/route.rb
158
+ - lib/gtfs/shape.rb
159
+ - lib/gtfs/source.rb
160
+ - lib/gtfs/stop.rb
161
+ - lib/gtfs/stop_time.rb
162
+ - lib/gtfs/trip.rb
163
+ - lib/gtfs/url_source.rb
164
+ - lib/gtfs/version.rb
165
+ - lib/gtfs.rb
166
+ - spec/fixtures/cassettes/invalid_gtfs_uri.yml
167
+ - spec/fixtures/cassettes/valid_gtfs_uri.yml
168
+ - spec/fixtures/missing_files.zip
169
+ - spec/fixtures/valid_gtfs.zip
170
+ - spec/gtfs/agency_spec.rb
171
+ - spec/gtfs/calendar_date_spec.rb
172
+ - spec/gtfs/calendar_spec.rb
173
+ - spec/gtfs/local_source_spec.rb
174
+ - spec/gtfs/route_spec.rb
175
+ - spec/gtfs/shape_spec.rb
176
+ - spec/gtfs/source_spec.rb
177
+ - spec/gtfs/stop_spec.rb
178
+ - spec/gtfs/stop_time_spec.rb
179
+ - spec/gtfs/trip_spec.rb
180
+ - spec/gtfs/url_source_spec.rb
181
+ - spec/spec_helper.rb
182
+ - spec/support/model_shared_examples.rb
183
+ - README.md
184
+ homepage: https://github.com/nerdEd/gtfs
185
+ licenses: []
186
+ post_install_message:
187
+ rdoc_options: []
188
+ require_paths:
189
+ - lib
190
+ required_ruby_version: !ruby/object:Gem::Requirement
191
+ none: false
192
+ requirements:
193
+ - - ! '>='
194
+ - !ruby/object:Gem::Version
195
+ version: '0'
196
+ required_rubygems_version: !ruby/object:Gem::Requirement
197
+ none: false
198
+ requirements:
199
+ - - ! '>='
200
+ - !ruby/object:Gem::Version
201
+ version: '0'
202
+ requirements: []
203
+ rubyforge_project:
204
+ rubygems_version: 1.8.24
205
+ signing_key:
206
+ specification_version: 3
207
+ summary: Load and read GTFS data from zip bundles
208
+ test_files: []