caltrain 0.0.6 → 0.0.7

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,15 @@
1
+ module DataParser
2
+ class << self
3
+ def data
4
+ @data ||= {}
5
+ end
6
+
7
+ def parse(file_path)
8
+ data[file_path] ||= File.read(file_path).
9
+ split(/[\n\r]+/)[1..-1].
10
+ map { |line| line.gsub('"', '').
11
+ gsub(/\s+/, ' ').
12
+ split(/,+/) }
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,26 @@
1
+ module Printing
2
+ def print_trip(trip, time, options={})
3
+ start = options[:starting_at]
4
+ output = options[:output] || $stdout
5
+
6
+ output << train_info(trip, time) << "\n"
7
+ output << " " << stop_info(trip, start) << "\n"
8
+ end
9
+
10
+ def train_info(trip, time)
11
+ "#{time} - Train #{trip.train_no} (#{trip.type})"
12
+ end
13
+
14
+ def stop_info(trip, start=trip.stops.first)
15
+ string = trip.stops.join(' -> ')
16
+ "*#{string[(string =~ /\b#{start}\b/ || 0)..-1]}"
17
+ end
18
+
19
+ def pretty_hash(hash)
20
+ max_field_width = hash.values.map(&:size).max
21
+
22
+ hash.each do |key, value|
23
+ puts "%#{max_field_width}s #{key}" % value
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,93 @@
1
+ module Schedule
2
+ class << self
3
+ include Printing
4
+
5
+ def times_path
6
+ "#{Caltrain.base_dir}/data/google_transit/stop_times.txt"
7
+ end
8
+
9
+ def data
10
+ @data ||= DataParser.parse(times_path)
11
+ end
12
+
13
+ def list(loc, dir, output=$stdout)
14
+ trips = trips_with_times(loc, dir).select { |_, time| time > now }
15
+ options = {:output => output, :starting_at => loc}
16
+
17
+ trips.each { |trip, time| print_trip(trip, time, options) }
18
+ end
19
+
20
+ def next(loc, dir, output=$stdout)
21
+ trip = trips_with_times(loc, dir).find { |_, time| time > now }
22
+ options = {:output => output, :starting_at => loc}
23
+
24
+ print_trip(trip.first, trip.last, options)
25
+ end
26
+
27
+ def trips_with_times(loc, dir)
28
+ @trips_with_times ||= trips_for_today(dir).map do |trip|
29
+ if time = trip.time_at_location(loc)
30
+ [trip, time]
31
+ end
32
+ end.compact.sort_by_nth(1)
33
+ end
34
+
35
+ def trips_for_today(dir)
36
+ if weekend?
37
+ Trip.weekend(dir)
38
+ elsif saturday?
39
+ Trip.saturday_only(dir)
40
+ else
41
+ Trip.weekday(dir)
42
+ end
43
+ end
44
+
45
+ def now
46
+ Time.now.strftime('%H:%M:%S')
47
+ end
48
+
49
+ def weekend?
50
+ saturday? || Time.now.sunday?
51
+ end
52
+
53
+ def saturday?
54
+ Time.now.saturday?
55
+ end
56
+
57
+ def abbrevs
58
+ @abbrevs ||= {
59
+ :gil => "Gilroy",
60
+ :smt => "San Martin",
61
+ :mrg => "Morgan Hill",
62
+ :bhl => "Blossom Hill",
63
+ :cap => "Capitol",
64
+ :tam => "Tamien",
65
+ :sj => "San Jose",
66
+ :clp => "College Park",
67
+ :sc => "Santa Clara",
68
+ :law => "Lawrence",
69
+ :sv => "Sunnyvale",
70
+ :mv => "Mountain View",
71
+ :sa => "San Antonio",
72
+ :cal => "California Ave",
73
+ :pa => "Palo Alto",
74
+ :men => "Menlo Park",
75
+ :ath => "Atherton",
76
+ :rc => "Redwood City",
77
+ :scl => "San Carlos",
78
+ :bel => "Belmont",
79
+ :hil => "Hillsdale",
80
+ :hay => "Hayward Park",
81
+ :sm => "San Mateo",
82
+ :brl => "Burlingame",
83
+ :bdw => "Broadway",
84
+ :mil => "Millbrae",
85
+ :sb => "San Bruno",
86
+ :ssf => "So. San Francisco",
87
+ :bsh => "Bayshore",
88
+ :tt => "22nd Street",
89
+ :sf => "San Francisco"
90
+ }.freeze
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,86 @@
1
+ class Trip
2
+ attr_reader :trip_id, :route_id, :service_id, :headsign, :direction, :shape_id
3
+
4
+ class << self
5
+ def trips_path
6
+ "#{Caltrain.base_dir}/data/google_transit/trips.txt"
7
+ end
8
+
9
+ def data
10
+ DataParser.parse(trips_path)
11
+ end
12
+
13
+ def new_from_data(data)
14
+ new(*data)
15
+ end
16
+
17
+ def trips(dir=nil)
18
+ @trips ||= []
19
+ [:north, :south].include?(dir) ? @trips.select { |trip| trip.direction == dir } : @trips
20
+ end
21
+
22
+ def weekend(dir=nil)
23
+ trips(dir).select { |trip| trip.service_id =~ /^WE/ }
24
+ end
25
+
26
+ def weekday(dir=nil)
27
+ trips(dir).select { |trip| trip.service_id =~ /^WD/ }
28
+ end
29
+
30
+ def saturday_only(dir=nil)
31
+ trips(dir).select { |trip| trip.service_id =~ /^ST/ }
32
+ end
33
+
34
+ def today(dir=nil)
35
+ if Schedule.saturday?
36
+ weekend(dir) + saturday_only(dir)
37
+ elsif Schedule.weekend?
38
+ weekend(dir)
39
+ else
40
+ weekday(dir)
41
+ end
42
+ end
43
+
44
+ def <<(trip)
45
+ @trips << trip unless trips.map(&:trip_id).include?(trip.trip_id)
46
+ end
47
+ end
48
+
49
+ def initialize(*data)
50
+ @trip_id = data[0]
51
+ @route_id = data[1]
52
+ @service_id = data[2]
53
+ @headsign = data[3]
54
+ @direction = data[4] == '0' ? :north : :south
55
+ @shape_id = data[5]
56
+
57
+ Trip << self
58
+ end
59
+
60
+ def train_no
61
+ @trip_id =~ /^(\d+)_.+$/; $1.to_i
62
+ end
63
+
64
+ def type
65
+ @route_id =~ /^ct_(\w+)_\d+/; $1
66
+ end
67
+
68
+ def time_data
69
+ @time_data ||= Schedule.data.select { |row| row[0] == @trip_id }
70
+ end
71
+
72
+ def times
73
+ @times ||= time_data.map_nth(1)
74
+ end
75
+
76
+ def time_at_location(loc)
77
+ return nil if loc == stops.last
78
+ loc_str = Schedule.abbrevs[loc]
79
+ time_data.find { |row| row[3] =~ /^#{loc_str}/ }[1] rescue nil
80
+ end
81
+
82
+ def stops(dir=@direction)
83
+ @stops ||= Schedule.abbrevs.select { |_, v| time_data.map_nth(3).any? { |d| d =~ /^#{v}/ } }.keys
84
+ dir == :north ? @stops : @stops.reverse
85
+ end
86
+ end
data/lib/caltrain.rb CHANGED
@@ -1,134 +1,56 @@
1
- class Caltrain
2
- class << self
3
- def base_dir
4
- File.expand_path('..', File.dirname(__FILE__))
5
- end
6
-
7
- def times_path
8
- "#{base_dir}/data/google_transit/stop_times.txt"
9
- end
10
-
11
- def trips_path
12
- "#{base_dir}/data/google_transit/trips.txt"
13
- end
14
-
15
- def upcoming_departures(loc, dir)
16
- times(loc, dir).select { |time| time > now }.sort
17
- end
18
-
19
- def next_departure(loc, dir)
20
- times(loc, dir).find { |time| time > now }
21
- end
22
-
23
- def times(loc, dir)
24
- @times ||= times_for_location(loc).select { |line| trip_ids_for_direction(dir).include?(line[0]) }.map {|i| i[1]}.sort
25
- end
26
-
27
- def trip_ids_for_direction(dir)
28
- @trip_ids_for_direction ||= trips_for_time_of_week.select {|trip| trip[4] == (dir == :north ? '0' : '1') }.map(&:first)
29
- end
30
-
31
- def trips_for_time_of_week
32
- @trips_for_time_of_week ||= all_trips.select { |trip| trip[2] =~ (weekend? ? /^WE/ : /^WD/) }
33
- end
34
-
35
- def times_for_location(loc)
36
- @times_for_location ||= all_times.select { |arr| arr[3] =~ /^#{abbrevs[loc]}/ }
37
- end
1
+ require 'core_ext'
38
2
 
39
- def all_times
40
- @all_times ||= File.read(times_path).split(/[\n\r]+/)[1..-1].map { |line| line.gsub('"', '').split(/,+/) }
41
- end
42
-
43
- def all_trips
44
- @all_trips ||= File.read(trips_path).split(/[\n\r]+/)[1..-1].map { |line| line.gsub('"', '').split(/,+/) }.sort
45
- end
46
-
47
- def weekend?
48
- @weekend ||= (Time.now.saturday? || Time.now.sunday?)
49
- end
3
+ module Caltrain
4
+ require 'caltrain/data_parser'
5
+ require 'caltrain/trip'
6
+ require 'caltrain/printing'
7
+ require 'caltrain/schedule'
50
8
 
51
- def now
52
- @now ||= Time.now.strftime('%H:%M:%S')
53
- end
54
-
55
- def abbrevs
56
- {
57
- :tt => "22nd Street",
58
- :ath => "Atherton",
59
- :bsh => "Bayshore",
60
- :bel => "Belmont",
61
- :bhl => "Blossom Hill",
62
- :bdw => "Broadway",
63
- :brl => "Burlingame",
64
- :cal => "California Ave",
65
- :cap => "Capitol",
66
- :clp => "College Park",
67
- :gil => "Gilroy",
68
- :hay => "Hayward Park",
69
- :hil => "Hillsdale",
70
- :law => "Lawrence",
71
- :men => "Menlo Park",
72
- :mil => "Millbrae",
73
- :mrg => "Morgan Hill",
74
- :mv => "Mountain View",
75
- :pa => "Palo Alto",
76
- :rc => "Redwood City",
77
- :sa => "San Antonio",
78
- :sb => "San Bruno",
79
- :scl => "San Carlos",
80
- :sf => "San Francisco",
81
- :sj => "San Jose",
82
- :smt => "San Martin",
83
- :sm => "San Mateo",
84
- :sc => "Santa Clara",
85
- :ssf => "So. San Francisco",
86
- :sv => "Sunnyvale",
87
- :tam => "Tamien"
88
- }
89
- end
90
-
91
- def pretty_abbrevs
92
- max_field_width = abbrevs.values.map(&:size).max
9
+ class << self
10
+ include Printing
93
11
 
94
- abbrevs.values.zip(abbrevs.keys).each do |name, abr|
95
- puts "%#{max_field_width}s #{abr}" % name
96
- end
12
+ def base_dir
13
+ File.expand_path('..', File.dirname(__FILE__))
97
14
  end
98
15
 
99
16
  def usage
100
17
  puts "Usage:"
101
- puts " caltrain <action> <location> <direction>"
102
- puts " action => [ next | list ]"
18
+ puts " caltrain <location> <direction> [ list | next ]"
103
19
  puts ""
104
20
  puts "Abbreviations:"
105
- pretty_abbrevs
21
+ pretty_hash(Schedule.abbrevs)
106
22
  exit(1)
107
23
  end
108
24
 
109
- def actions
110
- { :list => :upcoming_departures, :next => :next_departure }
111
- end
112
-
113
25
  def clean!
114
- instance_variables.each { |i| instance_variable_set(i, nil) }
26
+ [self, Trip].each do |klass|
27
+ klass.instance_variables.each { |i| klass.instance_variable_set(i, nil) }
28
+ end
115
29
  true
116
30
  end
117
31
 
118
32
  def run!(args)
119
- begin
120
- act, loc, dir = *args
121
-
122
- if dir =~ /^n/
123
- puts method(actions[act.to_sym]).call(loc.to_sym, :north)
124
- elsif dir =~ /^s/
125
- puts method(actions[act.to_sym]).call(loc.to_sym, :south)
126
- else
127
- raise
128
- end
129
- rescue
130
- usage
33
+ loc, dir, act = *args
34
+ loc = loc.to_sym
35
+ act = :next unless act
36
+
37
+ populate_trips!
38
+
39
+ if dir =~ /^n/i
40
+ Schedule.method(act).call(loc, :north)
41
+ elsif dir =~ /^s/i
42
+ Schedule.method(act).call(loc, :south)
43
+ else
44
+ raise
131
45
  end
46
+ rescue
47
+ usage
48
+ end
49
+
50
+ private
51
+
52
+ def populate_trips!
53
+ DataParser.parse(Trip.trips_path).each { |args| Trip.new_from_data(args) }
132
54
  end
133
55
  end
134
56
  end
data/lib/core_ext.rb ADDED
@@ -0,0 +1,9 @@
1
+ class Array
2
+ def map_nth(n)
3
+ map { |elem| elem[n] } rescue self
4
+ end
5
+
6
+ def sort_by_nth(n)
7
+ sort_by { |elem| elem[n] } rescue self
8
+ end
9
+ end
@@ -1,99 +1,5 @@
1
- require 'minitest/autorun'
2
- require 'minitest/pride'
3
- require 'mocha'
4
-
5
- require File.expand_path('../lib/caltrain', File.dirname(__FILE__))
6
-
7
1
  describe Caltrain do
8
- before { Caltrain.stubs(:weekend?).returns(false) }
9
-
10
- after { Caltrain.clean! }
11
-
12
2
  it 'has a base directory' do
13
3
  Caltrain.base_dir.must_equal(File.expand_path('..', File.dirname(__FILE__)))
14
4
  end
15
-
16
- describe 'trips' do
17
- it 'should parse trips.txt depending on the day of the week' do
18
- Caltrain.all_trips.first.must_equal(['101_20110701','ct_local_20110701','WD_20110701','San Francisco (Train 101)','0','cal_sj_sf'])
19
- end
20
- end
21
-
22
- describe 'times' do
23
- it 'should parse stop_times.txt correctly' do
24
- line = ['280_20110701','18:50:00','18:50:00','Mountain View Caltrain','10']
25
- Caltrain.all_times.must_include(line)
26
- end
27
-
28
- it 'should return times for a location' do
29
- ['16:58:00', '08:13:00', '19:44:00'].each do |time|
30
- Caltrain.times_for_location(:sv).map {|i| i[1]}.must_include(time)
31
- end
32
- end
33
- end
34
-
35
- describe '#next_departure' do
36
- it 'should return the next departure for north' do
37
- Caltrain.stubs(:now).returns('08:05:12')
38
- Caltrain.next_departure(:sv, :north).must_equal('08:13:00')
39
- end
40
-
41
- it 'should return the next departure for south' do
42
- Caltrain.stubs(:now).returns('18:50:00')
43
- Caltrain.next_departure(:sf, :south).must_equal('18:56:00')
44
- end
45
- end
46
-
47
- describe '#upcoming_departures' do
48
- it 'should return the upcoming trips for north' do
49
- Caltrain.stubs(:now).returns('08:05:12')
50
- upcoming1 = Caltrain.upcoming_departures(:sv, :north)
51
- upcoming1.must_include('08:18:00')
52
- upcoming1.wont_include('09:55:00')
53
- upcoming1.wont_include('09:14:00')
54
- end
55
-
56
- it 'should return upcoming trips for south' do
57
- Caltrain.stubs(:now).returns('18:30:10')
58
- upcoming2 = Caltrain.upcoming_departures(:sf, :south)
59
- upcoming2.must_include('18:33:00')
60
- upcoming2.wont_include('18:44:00')
61
- upcoming2.wont_include('18:59:00')
62
- end
63
- end
64
-
65
- describe 'weekend versus weekday' do
66
- it 'should pick weekday times' do
67
- Caltrain.stubs(:now).returns('09:10:10')
68
-
69
- Caltrain.next_departure(:mv, :north).must_equal('09:29:00')
70
-
71
- upcoming = Caltrain.upcoming_departures(:mv, :north)
72
- upcoming.must_include('16:37:00')
73
- upcoming.wont_include('09:19:00')
74
- end
75
-
76
- it 'should pick weekend times' do
77
- Caltrain.stubs(:weekend?).returns(true)
78
- Caltrain.stubs(:now).returns('07:46:15')
79
-
80
- Caltrain.next_departure(:sj, :north).must_equal('08:00:00')
81
-
82
- upcoming = Caltrain.upcoming_departures(:sj, :south)
83
- upcoming.must_include('12:00:00')
84
- upcoming.wont_include('07:50:00')
85
- end
86
- end
87
-
88
- describe 'excluding last stops' do
89
- it 'should not include times for last sf stop' do
90
- Caltrain.stubs(:now).returns('18:58:30')
91
- Caltrain.next_departure(:sf, :south).must_equal('19:30:00')
92
- end
93
-
94
- it 'should not include times for last sj stop' do
95
- Caltrain.stubs(:now).returns('08:12:10')
96
- Caltrain.next_departure(:sj, :north).must_equal('08:22:00')
97
- end
98
- end
99
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: caltrain
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.7
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -13,7 +13,7 @@ date: 2012-03-07 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: mocha
16
- requirement: &2151812960 !ruby/object:Gem::Requirement
16
+ requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,7 +21,12 @@ dependencies:
21
21
  version: '0'
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *2151812960
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
25
30
  description: A command line tool to easily figure out when the next caltrain leaves.
26
31
  email: alexgenco@gmail.com
27
32
  executables:
@@ -29,17 +34,14 @@ executables:
29
34
  extensions: []
30
35
  extra_rdoc_files: []
31
36
  files:
37
+ - lib/caltrain/data_parser.rb
38
+ - lib/caltrain/printing.rb
39
+ - lib/caltrain/schedule.rb
40
+ - lib/caltrain/trip.rb
32
41
  - lib/caltrain.rb
42
+ - lib/core_ext.rb
33
43
  - bin/caltrain
34
- - data/google_transit/agency.txt
35
- - data/google_transit/calendar.txt
36
- - data/google_transit/calendar_dates.txt
37
- - data/google_transit/fare_attributes.txt
38
- - data/google_transit/fare_rules.txt
39
- - data/google_transit/routes.txt
40
- - data/google_transit/shapes.txt
41
44
  - data/google_transit/stop_times.txt
42
- - data/google_transit/stops.txt
43
45
  - data/google_transit/trips.txt
44
46
  - spec/caltrain_spec.rb
45
47
  homepage: http://github.com/alexgenco/caltrain
@@ -62,7 +64,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
62
64
  version: '0'
63
65
  requirements: []
64
66
  rubyforge_project:
65
- rubygems_version: 1.8.17
67
+ rubygems_version: 1.8.24
66
68
  signing_key:
67
69
  specification_version: 3
68
70
  summary: Get the next caltrain
@@ -1,2 +0,0 @@
1
- agency_id,agency_name,agency_url,agency_timezone,agency_phone,agency_lang
2
- "caltrain-ca-us","Caltrain","http://www.caltrain.com","America/Los_Angeles","800-660-4287","en"
@@ -1,5 +0,0 @@
1
- service_id,monday,tuesday,wednesday,thursday,friday,saturday,sunday,start_date,end_date
2
- "ST_20110701","0","0","0","0","0","1","0","20110701","20120219"
3
- "WD_20110701","1","1","1","1","1","0","0","20110701","20160701"
4
- "WE_20110701","0","0","0","0","0","1","1","20110701","20160701"
5
- "ST_20120220","0","0","0","0","0","1","0","20120220","20120220"
@@ -1,6 +0,0 @@
1
- service_id,date,exception_type
2
- "SN_20110701","20111226","1"
3
- "WD_20110701","20111226","2"
4
- "WD_20110701","20120102","2"
5
- "SN_20110701","20120102","1"
6
-
@@ -1,13 +0,0 @@
1
- fare_id,price,currency_type,payment_method,transfers,transfer_duration
2
- "OW_1_20110701",2.7500,"USD","1",,
3
- "OW_2_20110701",4.7500,"USD","1",,
4
- "OW_3_20110701",6.7500,"USD","1",,
5
- "OW_4_20110701",8.7500,"USD","1",,
6
- "OW_5_20110701",10.7500,"USD","1",,
7
- "OW_6_20110701",12.7500,"USD","1",,
8
- "OW_1_20120220",2.7500,"USD","1",,
9
- "OW_2_20120220",4.7500,"USD","1",,
10
- "OW_3_20120220",6.7500,"USD","1",,
11
- "OW_4_20120220",8.7500,"USD","1",,
12
- "OW_5_20120220",10.7500,"USD","1",,
13
- "OW_6_20120220",12.7500,"USD","1",,