gtfs 0.1.0 → 0.2.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.
@@ -0,0 +1,4 @@
1
+ Session.vim
2
+ coverage
3
+ .rvmrc
4
+ *.gem
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.2
4
+ - 1.9.3
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gem 'rake'
4
+ gem 'rspec'
5
+ gem 'multi_json', '1.0.4'
6
+ gem 'simplecov', :require => false
7
+ gem 'rubyzip'
8
+ gem 'vcr'
9
+ gem 'fakeweb'
@@ -0,0 +1,33 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ diff-lcs (1.1.3)
5
+ fakeweb (1.3.0)
6
+ multi_json (1.0.4)
7
+ rake (0.9.2.2)
8
+ rspec (2.8.0)
9
+ rspec-core (~> 2.8.0)
10
+ rspec-expectations (~> 2.8.0)
11
+ rspec-mocks (~> 2.8.0)
12
+ rspec-core (2.8.0)
13
+ rspec-expectations (2.8.0)
14
+ diff-lcs (~> 1.1.2)
15
+ rspec-mocks (2.8.0)
16
+ rubyzip (0.9.5)
17
+ simplecov (0.6.1)
18
+ multi_json (~> 1.0)
19
+ simplecov-html (~> 0.5.3)
20
+ simplecov-html (0.5.3)
21
+ vcr (1.11.3)
22
+
23
+ PLATFORMS
24
+ ruby
25
+
26
+ DEPENDENCIES
27
+ fakeweb
28
+ multi_json (= 1.0.4)
29
+ rake
30
+ rspec
31
+ rubyzip
32
+ simplecov
33
+ vcr
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  ### GTFS Ruby
2
2
 
3
- A Ruby wrapper for the General Transit Feed Specification
3
+ A Ruby wrapper for the [General Transit Feed Specification](https://developers.google.com/transit/gtfs/)
4
4
 
5
5
  ### Getting started
6
6
 
@@ -15,10 +15,31 @@ Accessing GTFS data from the source:
15
15
  source.routes
16
16
  source.trips
17
17
  source.stop_times
18
- source.calendar
19
- source.calendar_dates
20
- source.fare_attributes
21
- source.fare_rules
18
+ source.calendars
19
+ source.calendar_dates
20
+ source.fare_attributes
21
+ source.fare_rules
22
22
  source.shapes
23
- source.frequencies
24
- source.transfers
23
+ source.frequencies
24
+ source.transfers
25
+
26
+ ### License
27
+
28
+ Copyright (C) 2012 Ed Schmalzle
29
+
30
+ Permission is hereby granted, free of charge, to any person obtaining a
31
+ copy of this software and associated documentation files (the "Software"), to
32
+ deal in the Software without restriction, including without limitation the
33
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
34
+ copies of the Software, and to permit persons to whom the Software is furnished
35
+ to do so, subject to the following conditions:
36
+
37
+ The above copyright notice and this permission notice shall be included in
38
+ all copies or substantial portions of the Software.
39
+
40
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
41
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
42
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
43
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
44
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
45
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile CHANGED
@@ -1,7 +1,6 @@
1
- #!/usr/bin/env rake
2
1
  require 'rubygems'
3
2
  require 'rspec/core/rake_task'
4
3
 
5
4
  RSpec::Core::RakeTask.new do |t|
6
- t.pattern = "./spec/**/*_spec.rb"
5
+ t.pattern = './spec/**/*_spec.rb'
7
6
  end
@@ -0,0 +1,32 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path('../lib', __FILE__)
3
+ require './lib/gtfs/version'
4
+
5
+ Gem::Specification.new do |gem|
6
+ gem.name = 'gtfs'
7
+ gem.version = GTFS::VERSION
8
+ gem.date = Date.today.to_s
9
+
10
+ gem.summary = 'Load and read GTFS data from zip bundles'
11
+ gem.description = 'gtfs reads GTFS data from a google-compliant Zip bundle
12
+ and returns an object representing the CSV data inside'
13
+
14
+ gem.authors = ['nerdEd']
15
+ gem.email = ['ed@nerded.net']
16
+ gem.homepage = 'https://github.com/nerdEd/gtfs'
17
+
18
+ gem.add_dependency 'rake'
19
+ gem.add_dependency 'multi_json'
20
+ gem.add_dependency 'rubyzip'
21
+
22
+ gem.add_development_dependency 'rspec', ['>= 2.0.0']
23
+ gem.add_development_dependency 'simplecov'
24
+ gem.add_development_dependency 'ruby-debug19'
25
+ gem.add_development_dependency 'vcr'
26
+ gem.add_development_dependency 'fakeweb'
27
+
28
+ gem.files = `git ls-files`.split("\n")
29
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
30
+
31
+ gem.require_paths = ['lib']
32
+ end
@@ -3,12 +3,17 @@ require 'gtfs/model'
3
3
  require 'gtfs/agency'
4
4
  require 'gtfs/calendar'
5
5
  require 'gtfs/calendar_date'
6
- require 'gtfs/source'
7
- require 'gtfs/url_source'
8
- require 'gtfs/local_source'
9
6
  require 'gtfs/route'
10
7
  require 'gtfs/shape'
11
8
  require 'gtfs/stop'
12
9
  require 'gtfs/stop_time'
13
10
  require 'gtfs/trip'
14
11
  require 'gtfs/custom_exceptions'
12
+ require 'gtfs/fare_attribute'
13
+ require 'gtfs/fare_rule'
14
+ require 'gtfs/frequency'
15
+ require 'gtfs/transfer'
16
+
17
+ require 'gtfs/source'
18
+ require 'gtfs/url_source'
19
+ require 'gtfs/local_source'
@@ -8,6 +8,10 @@ module GTFS
8
8
 
9
9
  column_prefix :agency_
10
10
 
11
+ collection_name :agencies
12
+ required_file true
13
+ uses_filename 'agency.txt'
14
+
11
15
  def self.parse_agencies(data)
12
16
  return parse_models(data)
13
17
  end
@@ -5,6 +5,10 @@ module GTFS
5
5
  has_required_attrs :service_id, :monday, :tuesday, :wednesday, :thursday, :friday, :saturday, :sunday, :start_date, :end_date
6
6
  attr_accessor *attrs
7
7
 
8
+ collection_name :calendars
9
+ required_file true
10
+ uses_filename 'calendars.txt'
11
+
8
12
  def self.parse_calendars(data)
9
13
  return parse_models(data)
10
14
  end
@@ -5,6 +5,10 @@ module GTFS
5
5
  has_required_attrs :service_id, :date, :exception_type
6
6
  attr_accessor *attrs
7
7
 
8
+ collection_name :calendar_dates
9
+ required_file true
10
+ uses_filename 'calendar_dates.txt'
11
+
8
12
  def self.parse_calendar_dates(data)
9
13
  return parse_models(data)
10
14
  end
@@ -0,0 +1,17 @@
1
+ module GTFS
2
+ class FareAttribute
3
+ include GTFS::Model
4
+
5
+ has_required_attrs :fare_id, :price, :currency_type, :payment_method, :transfers
6
+ has_optional_attrs :transfer_duration
7
+ attr_accessor *attrs
8
+
9
+ collection_name :fare_attributes
10
+ required_file false
11
+ uses_filename 'fare_attributes.txt'
12
+
13
+ def self.parse_fare_attributes(data)
14
+ return parse_models(data)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module GTFS
2
+ class FareRule
3
+ include GTFS::Model
4
+
5
+ has_required_attrs :fare_id
6
+ has_optional_attrs :route_id, :origin_id, :destination_id, :contains_id
7
+ attr_accessor *attrs
8
+
9
+ collection_name :fare_rules
10
+ required_file false
11
+ uses_filename 'fare_rules.txt'
12
+
13
+ def self.parse_fare_rules(data)
14
+ return parse_models(data)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module GTFS
2
+ class Frequency
3
+ include GTFS::Model
4
+
5
+ has_required_attrs :trip_id, :start_time, :end_time, :headway_secs
6
+ has_optional_attrs :exact_times
7
+ attr_accessor *attrs
8
+
9
+ collection_name :frequencies
10
+ required_file false
11
+ uses_filename 'frequencies.txt'
12
+
13
+ def self.parse_frequencies(data)
14
+ return parse_models(data)
15
+ end
16
+ end
17
+ end
@@ -1,4 +1,4 @@
1
- require 'CSV'
1
+ require 'csv'
2
2
 
3
3
  module GTFS
4
4
  module Model
@@ -58,6 +58,18 @@ module GTFS
58
58
  self.class_variable_set('@@prefix', prefix)
59
59
  end
60
60
 
61
+ def required_file(required)
62
+ self.define_singleton_method(:required_file?) {required}
63
+ end
64
+
65
+ def collection_name(collection_name)
66
+ self.define_singleton_method(:name) {collection_name}
67
+ end
68
+
69
+ def uses_filename(filename)
70
+ self.define_singleton_method(:filename) {filename}
71
+ end
72
+
61
73
  def parse_models(data)
62
74
  return [] if data.nil? || data.empty?
63
75
 
@@ -8,6 +8,10 @@ module GTFS
8
8
 
9
9
  column_prefix :route_
10
10
 
11
+ collection_name :routes
12
+ required_file true
13
+ uses_filename 'routes.txt'
14
+
11
15
  def self.parse_routes(data)
12
16
  return parse_models(data)
13
17
  end
@@ -6,6 +6,10 @@ module GTFS
6
6
  has_optional_attrs :dist_traveled
7
7
  attr_accessor *attrs
8
8
 
9
+ collection_name :shapes
10
+ required_file false
11
+ uses_filename 'shapes.txt'
12
+
9
13
  column_prefix :shape_
10
14
 
11
15
  def self.parse_shapes(data)
@@ -5,9 +5,13 @@ require 'zip/zip'
5
5
  module GTFS
6
6
  class Source
7
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
8
+ ENTITIES = [GTFS::Agency, GTFS::Stop, GTFS::Route, GTFS::Trip, GTFS::StopTime,
9
+ GTFS::Calendar, GTFS::CalendarDate, GTFS::Shape, GTFS::FareAttribute,
10
+ GTFS::FareRule, GTFS::Frequency, GTFS::Transfer]
11
+
12
+ REQUIRED_SOURCE_FILES = ENTITIES.select(&:required_file?).map(&:filename)
13
+ OPTIONAL_SOURCE_FILES = ENTITIES.reject(&:required_file?).map(&:filename)
14
+ SOURCE_FILES = ENTITIES.map(&:filename)
11
15
 
12
16
  attr_accessor :source, :archive
13
17
 
@@ -19,8 +23,6 @@ module GTFS
19
23
 
20
24
  @source = source
21
25
  load_archive(@source)
22
-
23
- raise InvalidSourceException.new('Missing required source files') if missing_sources?
24
26
  end
25
27
 
26
28
  def self.finalize(directory)
@@ -40,10 +42,10 @@ module GTFS
40
42
  end
41
43
 
42
44
  def self.build(data_root)
43
- if data_root.match(/http|www/)
44
- URLSource.new(data_root)
45
- else
45
+ if File.exists?(data_root)
46
46
  LocalSource.new(data_root)
47
+ else
48
+ URLSource.new(data_root)
47
49
  end
48
50
  end
49
51
 
@@ -51,64 +53,28 @@ module GTFS
51
53
  Dir.entries(@tmp_dir)
52
54
  end
53
55
 
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
56
+ def raise_if_missing_source(filename)
57
+ file_missing = !entries.include?(filename)
58
+ raise InvalidSourceException.new("Missing required source file: #{filename}") if file_missing
82
59
  end
83
60
 
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)
61
+ ENTITIES.each do |entity|
62
+ define_method entity.name.to_sym do
63
+ parse_file entity.filename do |f|
64
+ entity.send("parse_#{entity.name}".to_sym, f.read)
65
+ end
95
66
  end
96
- @shapes
97
67
  end
98
68
 
99
- def trips
100
- open(File.join(@tmp_dir, '/', 'trips.txt')) do |f|
101
- @trips ||= Trip.parse_trips(f.read)
102
- end
103
- @trips
69
+ def files
70
+ @files ||= {}
104
71
  end
105
72
 
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)
73
+ def parse_file(filename)
74
+ raise_if_missing_source filename
75
+ open File.join(@tmp_dir, '/', filename) do |f|
76
+ files[filename] ||= yield f
110
77
  end
111
- @stop_times
112
78
  end
113
79
  end
114
80
  end
@@ -7,6 +7,10 @@ module GTFS
7
7
  column_prefix :stop_
8
8
  attr_accessor *attrs
9
9
 
10
+ collection_name :stops
11
+ required_file true
12
+ uses_filename 'stops.txt'
13
+
10
14
  LOCATION_TYPE_STOP = 0
11
15
  LOCATION_TYPE_STATION = 1
12
16
 
@@ -6,6 +6,10 @@ module GTFS
6
6
  has_optional_attrs :stop_headsign, :pickup_type, :drop_off_type, :shape_dist_traveled
7
7
  attr_accessor *attrs
8
8
 
9
+ collection_name :stop_times
10
+ required_file true
11
+ uses_filename 'stop_times.txt'
12
+
9
13
  def self.parse_stop_times(data)
10
14
  return parse_models(data)
11
15
  end
@@ -0,0 +1,19 @@
1
+ module GTFS
2
+ class Transfer
3
+ include GTFS::Model
4
+
5
+ has_required_attrs :from_stop_id, :to_stop_id, :type
6
+ has_optional_attrs :min_transfer_time
7
+ attr_accessor *attrs
8
+
9
+ column_prefix :transfer_
10
+
11
+ collection_name :transfers
12
+ required_file false
13
+ uses_filename 'transfers.txt'
14
+
15
+ def self.parse_transfers(data)
16
+ return parse_models(data)
17
+ end
18
+ end
19
+ end
@@ -8,6 +8,10 @@ module GTFS
8
8
 
9
9
  column_prefix :trip_
10
10
 
11
+ collection_name :trips
12
+ required_file true
13
+ uses_filename 'trips.txt'
14
+
11
15
  def self.parse_trips(data)
12
16
  return parse_models(data)
13
17
  end
@@ -1,5 +1,5 @@
1
1
  require 'net/http'
2
- require 'URI'
2
+ require 'uri'
3
3
 
4
4
  module GTFS
5
5
  class URLSource < Source
@@ -1,4 +1,4 @@
1
1
  module GTFS
2
- VERSION = '0.1.0'
2
+ VERSION = '0.2.0'
3
3
  end
4
4
 
@@ -23,13 +23,11 @@ describe GTFS::Source do
23
23
 
24
24
  it {should == 'LocalSource'}
25
25
  end
26
- end
27
26
 
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
27
+ context 'with a file object as a data root' do
28
+ let(:data_source) {File.open(valid_local_source)}
29
+
30
+ it {should == 'LocalSource'}
33
31
  end
34
32
  end
35
33
 
@@ -55,6 +53,13 @@ describe GTFS::Source do
55
53
  end
56
54
 
57
55
  describe '#routes' do
56
+ context 'when the source is missing routes' do
57
+ let(:source) { GTFS::Source.build source_missing_required_files }
58
+
59
+ it do
60
+ expect { source.routes }.to raise_exception GTFS::InvalidSourceException
61
+ end
62
+ end
58
63
  end
59
64
 
60
65
  describe '#trips' do
@@ -7,7 +7,6 @@ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
7
7
  require 'bundler/setup'
8
8
  require 'rspec'
9
9
  require 'vcr'
10
- require 'ruby-debug'
11
10
  require 'gtfs'
12
11
 
13
12
  require File.expand_path(File.dirname(__FILE__) + '/support/model_shared_examples')
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gtfs
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-07-03 00:00:00.000000000 Z
12
+ date: 2012-12-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -139,19 +139,29 @@ dependencies:
139
139
  - - ! '>='
140
140
  - !ruby/object:Gem::Version
141
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
142
+ description: ! "gtfs reads GTFS data from a google-compliant Zip bundle \n and
143
+ returns an object representing the CSV data inside"
144
144
  email:
145
- - nerdEd
145
+ - ed@nerded.net
146
146
  executables: []
147
147
  extensions: []
148
148
  extra_rdoc_files: []
149
149
  files:
150
+ - .gitignore
151
+ - .travis.yml
152
+ - Gemfile
153
+ - Gemfile.lock
154
+ - README.md
150
155
  - Rakefile
156
+ - gtfs.gemspec
157
+ - lib/gtfs.rb
151
158
  - lib/gtfs/agency.rb
152
159
  - lib/gtfs/calendar.rb
153
160
  - lib/gtfs/calendar_date.rb
154
161
  - lib/gtfs/custom_exceptions.rb
162
+ - lib/gtfs/fare_attribute.rb
163
+ - lib/gtfs/fare_rule.rb
164
+ - lib/gtfs/frequency.rb
155
165
  - lib/gtfs/local_source.rb
156
166
  - lib/gtfs/model.rb
157
167
  - lib/gtfs/route.rb
@@ -159,10 +169,10 @@ files:
159
169
  - lib/gtfs/source.rb
160
170
  - lib/gtfs/stop.rb
161
171
  - lib/gtfs/stop_time.rb
172
+ - lib/gtfs/transfer.rb
162
173
  - lib/gtfs/trip.rb
163
174
  - lib/gtfs/url_source.rb
164
175
  - lib/gtfs/version.rb
165
- - lib/gtfs.rb
166
176
  - spec/fixtures/cassettes/invalid_gtfs_uri.yml
167
177
  - spec/fixtures/cassettes/valid_gtfs_uri.yml
168
178
  - spec/fixtures/missing_files.zip
@@ -180,7 +190,6 @@ files:
180
190
  - spec/gtfs/url_source_spec.rb
181
191
  - spec/spec_helper.rb
182
192
  - spec/support/model_shared_examples.rb
183
- - README.md
184
193
  homepage: https://github.com/nerdEd/gtfs
185
194
  licenses: []
186
195
  post_install_message:
@@ -205,4 +214,21 @@ rubygems_version: 1.8.24
205
214
  signing_key:
206
215
  specification_version: 3
207
216
  summary: Load and read GTFS data from zip bundles
208
- test_files: []
217
+ test_files:
218
+ - spec/fixtures/cassettes/invalid_gtfs_uri.yml
219
+ - spec/fixtures/cassettes/valid_gtfs_uri.yml
220
+ - spec/fixtures/missing_files.zip
221
+ - spec/fixtures/valid_gtfs.zip
222
+ - spec/gtfs/agency_spec.rb
223
+ - spec/gtfs/calendar_date_spec.rb
224
+ - spec/gtfs/calendar_spec.rb
225
+ - spec/gtfs/local_source_spec.rb
226
+ - spec/gtfs/route_spec.rb
227
+ - spec/gtfs/shape_spec.rb
228
+ - spec/gtfs/source_spec.rb
229
+ - spec/gtfs/stop_spec.rb
230
+ - spec/gtfs/stop_time_spec.rb
231
+ - spec/gtfs/trip_spec.rb
232
+ - spec/gtfs/url_source_spec.rb
233
+ - spec/spec_helper.rb
234
+ - spec/support/model_shared_examples.rb