bahn.rb 1.0.0 → 2.0.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/README.md +24 -0
- data/lib/bahn/bahn_agent.rb +39 -22
- data/lib/bahn/bahn_route.rb +62 -66
- data/lib/bahn/bahn_routepart.rb +15 -1
- data/lib/bahn/bahn_station.rb +30 -0
- data/lib/bahn.rb +6 -3
- metadata +7 -6
- data/lib/bahn/version.rb +0 -3
data/README.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
Load connections for public transportation from the m.bahn.de website.
|
|
2
|
+
|
|
3
|
+
This is under heavy development. Don't expect a working solution!
|
|
4
|
+
|
|
5
|
+
Example
|
|
6
|
+
=
|
|
7
|
+
require 'bahn.rb'
|
|
8
|
+
|
|
9
|
+
agent = Bahn::Agent.new
|
|
10
|
+
routes = agent.get_routes(
|
|
11
|
+
"Düsseldorf reisholz s bahn", # start address or station
|
|
12
|
+
"Düsseldorf, Heerdter Sandberg 40 ", # target address or station
|
|
13
|
+
:include_coords => true, # include coordinates of stations
|
|
14
|
+
:limit => 1, # how many connections?
|
|
15
|
+
:start_type => :station, # :station or :address
|
|
16
|
+
:target_type => :address # :station or :address
|
|
17
|
+
)
|
|
18
|
+
# output the connection info
|
|
19
|
+
routes.each {|route| route.parts.each {|part| puts part } }
|
|
20
|
+
|
|
21
|
+
How to help
|
|
22
|
+
=
|
|
23
|
+
Feel free to implement some additions, refactor and create a pull request!
|
|
24
|
+
... and create tests of course ;)
|
data/lib/bahn/bahn_agent.rb
CHANGED
|
@@ -8,7 +8,7 @@ module Bahn
|
|
|
8
8
|
# You can go even use far distances...
|
|
9
9
|
# routes = agent.get_routes "Heerdter Sandberg 35 Düsseldorf, Düsseldorf", "Berlin Hauptstraße 10"
|
|
10
10
|
# routes.each {|route| route.parts.each {|part| puts part } }
|
|
11
|
-
# => Am 2013-02-01 von 17:32 bis 17:33 : Düsseldorf - Oberkassel, Heerdter Sandberg
|
|
11
|
+
# => Am 2013-02-01 von 17:32 bis 17:33 : Düsseldorf - Oberkassel, Heerdter Sandberg 60 nach Heerdter Sandberg U, Düsseldorf via Fußweg
|
|
12
12
|
# => Am 2013-02-01 von 17:33 bis 17:47 : Heerdter Sandberg U, Düsseldorf nach Düsseldorf Hauptbahnhof via U 7
|
|
13
13
|
# => Am 2013-02-01 von 17:47 bis 17:53 : Düsseldorf Hauptbahnhof nach Düsseldorf Hbf via Fußweg
|
|
14
14
|
# => Am 2013-02-01 von 17:53 bis 22:22 : Düsseldorf Hbf nach Berlin Hbf via ICE 945
|
|
@@ -28,6 +28,12 @@ module Bahn
|
|
|
28
28
|
@@user_agent = val
|
|
29
29
|
end
|
|
30
30
|
|
|
31
|
+
TYPES =
|
|
32
|
+
{
|
|
33
|
+
:station => 1,
|
|
34
|
+
:address => 2
|
|
35
|
+
}.freeze
|
|
36
|
+
|
|
31
37
|
# Initialize a new Agent
|
|
32
38
|
# options:
|
|
33
39
|
# :user_agent => Set the user agent. Default: "bahn.rb"
|
|
@@ -41,41 +47,52 @@ module Bahn
|
|
|
41
47
|
# :start_type and :target_type should be the same, no other options is implemented yet
|
|
42
48
|
# Options:
|
|
43
49
|
# * :time => start time for the connection
|
|
44
|
-
# * :start_type =>
|
|
45
|
-
# * :target_type =>
|
|
50
|
+
# * :start_type => :station or :address
|
|
51
|
+
# * :target_type => :station or :address
|
|
52
|
+
# * :include_coords => Include coordiantes for the station. This takes a while especially for longer routes! default: true
|
|
46
53
|
# Returns:
|
|
47
54
|
# Array of Bahn::Route(s)
|
|
48
55
|
# Raises:
|
|
49
56
|
# "no_route" if no route could be found
|
|
50
57
|
def get_routes from, to, options = {}
|
|
51
|
-
options = {:time => Time.now, :start_type =>
|
|
58
|
+
options = {:time => Time.now, :start_type => :address, :target_type => :address, :depth => 0, :include_coords => true, :limit => 2}.merge(options)
|
|
59
|
+
options[:time] = options[:time] + 10.minutes # Ansonsten liegt die letzte Verbindung in der Vergangenheit
|
|
60
|
+
|
|
52
61
|
page = @agent.get @@options[:url_route]
|
|
53
62
|
form = page.forms.first
|
|
54
|
-
form["REQ0JourneyDate"] =
|
|
55
|
-
form["REQ0JourneyTime"] =
|
|
56
|
-
form["REQ0JourneyStopsS0A"] = options[:start_type]
|
|
57
|
-
form["REQ0JourneyStopsZ0A"] = options[:target_type]
|
|
63
|
+
form["REQ0JourneyDate"] = options[:time].strftime "%d.%m.%y"
|
|
64
|
+
form["REQ0JourneyTime"] = options[:time].to_formatted_s :time
|
|
65
|
+
form["REQ0JourneyStopsS0A"] = TYPES[options[:start_type]]
|
|
66
|
+
form["REQ0JourneyStopsZ0A"] = TYPES[options[:target_type]]
|
|
58
67
|
form["REQ0JourneyStopsS0G"] = from
|
|
59
|
-
form["REQ0JourneyStopsZ0G"] = to
|
|
68
|
+
form["REQ0JourneyStopsZ0G"] = to
|
|
69
|
+
form["REQ0JourneyProduct_prod_list"] = "4:0001111111000000"
|
|
60
70
|
result = form.submit(form.button_with(:value => "Suchen"))
|
|
61
71
|
|
|
62
|
-
type = :undefined
|
|
63
|
-
type = :door2door if options[:start_type] == 2 && options[:target_type] == 2
|
|
64
|
-
type = :station2station if options[:start_type] == 1 && options[:target_type] == 1
|
|
65
|
-
|
|
66
72
|
routes = []
|
|
67
73
|
links = result.links_with(:href => /details=opened!/)
|
|
68
|
-
links.each
|
|
69
|
-
page = link.click
|
|
70
|
-
routes << Route.new(page,
|
|
74
|
+
links.each do |link|
|
|
75
|
+
page = link.click
|
|
76
|
+
routes << Route.new(page, options)
|
|
77
|
+
break if routes.count == options[:limit]
|
|
71
78
|
end
|
|
72
79
|
|
|
73
80
|
# Keine Station gefunden und es werden keine Vorschläge angezeigt...
|
|
74
81
|
# also suchen wir nachder nächstbesten Adresse und nutzen dies
|
|
75
|
-
if links.count == 0 && options[:depth] == 0
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
82
|
+
if links.count == 0 && options[:depth] == 0
|
|
83
|
+
if options[:start_type] == :address
|
|
84
|
+
from = find_address(from).name
|
|
85
|
+
elsif options[:start_type] == :station
|
|
86
|
+
from = find_station(from).name
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
if options[:target_type] == :address
|
|
90
|
+
to = find_address(to).name
|
|
91
|
+
elsif options[:target_type] == :station
|
|
92
|
+
to = find_station(to).name
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
return get_routes from, to, options.merge(:depth => options[:depth]+1)
|
|
79
96
|
end
|
|
80
97
|
|
|
81
98
|
raise "no_route" if routes.count == 0 || links.count == 0
|
|
@@ -90,7 +107,7 @@ module Bahn
|
|
|
90
107
|
result = @agent.get("#{@@options[:uri_stations]}#{name}").body.gsub("SLs.sls=", "").gsub(";SLs.showSuggestion();", "")
|
|
91
108
|
# a Mechanize::File instead of a Page is returned so we have to convert manually
|
|
92
109
|
result = Iconv.conv("utf-8", "iso-8859-1", result)
|
|
93
|
-
|
|
110
|
+
Station.new(JSON.parse(result)["suggestions"].first)
|
|
94
111
|
end
|
|
95
112
|
|
|
96
113
|
# Finds the first usable address for the given parameter. The returned address can then be used for further processing in routes
|
|
@@ -101,7 +118,7 @@ module Bahn
|
|
|
101
118
|
result = @agent.get("#{@@options[:uri_adresses]}#{address}").body.gsub("SLs.sls=", "").gsub(";SLs.showSuggestion();", "")
|
|
102
119
|
# a Mechanize::File instead of a Page is returned so we have to convert manually
|
|
103
120
|
result = Iconv.conv("utf-8", "iso-8859-1", result)
|
|
104
|
-
JSON.parse(result)["suggestions"].first
|
|
121
|
+
Station.new(JSON.parse(result)["suggestions"].first)
|
|
105
122
|
end
|
|
106
123
|
end
|
|
107
124
|
end
|
data/lib/bahn/bahn_route.rb
CHANGED
|
@@ -4,40 +4,72 @@ module Bahn
|
|
|
4
4
|
# At the end you'll have a nice step by step navigation
|
|
5
5
|
# Feel free to refactor ;)
|
|
6
6
|
class Route
|
|
7
|
-
|
|
8
|
-
attr_accessor :price, :type, :parts
|
|
7
|
+
attr_accessor :price, :parts, :notes, :start_type, :target_type
|
|
9
8
|
|
|
10
9
|
# Initialize with a Mechanize::Page and a specific type
|
|
11
10
|
# The page should be the detail view of m.bahn.de
|
|
12
11
|
# Parameters:
|
|
13
12
|
# * page => Mechanize::Page
|
|
14
|
-
#
|
|
15
|
-
def initialize page,
|
|
13
|
+
# * type => :door2door or :station2station
|
|
14
|
+
def initialize page, options = {}
|
|
15
|
+
options = {:start_type => :address, :target_type => :address, :include_coords => true}.merge(options)
|
|
16
|
+
@do_load = options[:include_coords]
|
|
17
|
+
self.start_type = options[:start_type]
|
|
18
|
+
self.target_type = options[:target_type]
|
|
16
19
|
summary_time = page.search("//div[contains(@class, 'querysummary2')]").text.gsub("\n", " ").strip
|
|
17
20
|
html_parts = page.search("//div[contains(@class, 'haupt')]")
|
|
18
21
|
price = html_parts.pop.text
|
|
19
22
|
html_parts.pop
|
|
20
|
-
@type = type
|
|
21
23
|
|
|
22
24
|
route = ""
|
|
23
25
|
html_parts.each do |part|
|
|
24
26
|
text = part.text.strip
|
|
25
27
|
next if text.start_with? "Reiseprofil" # not important
|
|
28
|
+
if text.starts_with?("Hinweis", "Aktuelle Informationen")
|
|
29
|
+
self.notes = "#{self.notes}\n#{text}" if !text.include?("Start/Ziel mit äquivalentem Bahnhof ersetzt")
|
|
30
|
+
next
|
|
31
|
+
end
|
|
32
|
+
|
|
26
33
|
route << text << "\n"
|
|
27
34
|
end
|
|
28
|
-
route = route.split("\n")
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
35
|
+
route = route.split("\n")
|
|
36
|
+
|
|
37
|
+
idx = 3
|
|
38
|
+
@start = RoutePart.new
|
|
39
|
+
@target = RoutePart.new
|
|
40
|
+
if options[:start_type] == :address
|
|
41
|
+
@start.start = Station.new({"value" => route[0], :load => :foot, :do_load => @do_load})
|
|
42
|
+
@start.type = "Fußweg" # route[2]
|
|
43
|
+
@start.end_time = DateTime.parse(summary_time.split("-").first.gsub(".13", ".2013"))
|
|
44
|
+
@start.start_time = @start.end_time - route[1].to_i.minutes
|
|
45
|
+
@start.target = route[3]
|
|
46
|
+
elsif options[:start_type] == :station
|
|
47
|
+
@start.start = Station.new({"value" => route[0], :load => :station, :do_load => @do_load})
|
|
48
|
+
@start.start_time = DateTime.parse(@date.to_s + route[1])
|
|
49
|
+
@start.type = route[2]
|
|
50
|
+
@start.end_time = DateTime.parse(@date.to_s + route[3])
|
|
51
|
+
@start.target = Station.new({"value" => route[4], :load => :station, :do_load => @do_load})
|
|
52
|
+
idx = 4
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
@date = @start.start_time.to_date # otherwise all dates will be "today"
|
|
56
|
+
create_parts idx, route
|
|
57
|
+
if options[:target_type] == :station
|
|
58
|
+
@target = @parts.last
|
|
59
|
+
elsif options[:target_type] == :address
|
|
60
|
+
@target.type = "Fußweg"
|
|
61
|
+
@target.target = Station.new({"value" => route.last, :load => :foot, :do_load => @do_load})
|
|
62
|
+
if summary_time.split("-").last.strip.length != 5
|
|
63
|
+
# Date is included in the string
|
|
64
|
+
@target.end_time = DateTime.parse(summary_time.split("-").last.gsub(".13", ".2013"))
|
|
65
|
+
else
|
|
66
|
+
# no date given, use start date
|
|
67
|
+
@target.end_time = DateTime.parse("#{@start.start_time.to_date} #{summary_time.split("-").last}")
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
@target.end_time += route[route.length-3].to_i.minutes
|
|
71
|
+
@parts << @target
|
|
72
|
+
end
|
|
41
73
|
end
|
|
42
74
|
|
|
43
75
|
# Start time of the route
|
|
@@ -47,7 +79,7 @@ module Bahn
|
|
|
47
79
|
|
|
48
80
|
# End time of the route
|
|
49
81
|
def end_time
|
|
50
|
-
@parts.last.
|
|
82
|
+
@parts.last.end_time
|
|
51
83
|
end
|
|
52
84
|
|
|
53
85
|
# Starting point of the route
|
|
@@ -62,74 +94,33 @@ module Bahn
|
|
|
62
94
|
|
|
63
95
|
private
|
|
64
96
|
|
|
65
|
-
# Create the station 2 station route parts...
|
|
66
|
-
def create_station2station route
|
|
67
|
-
@start = RoutePart.new
|
|
68
|
-
@start.start = route[0]
|
|
69
|
-
@start.start_time = DateTime.parse(@date.to_s + route[1])
|
|
70
|
-
@start.type = route[2]
|
|
71
|
-
@start.end_time = DateTime.parse(@date.to_s + route[3])
|
|
72
|
-
@start.target = route[4]
|
|
73
|
-
|
|
74
|
-
@target = RoutePart.new # avoid nullpointer
|
|
75
|
-
|
|
76
|
-
@parts = [@start]
|
|
77
|
-
create_parts 0, route
|
|
78
|
-
@target = @parts.last
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
# Create the door 2 door route parts
|
|
82
|
-
def create_door2door route, summary_time
|
|
83
|
-
@start = RoutePart.new
|
|
84
|
-
@start.start = route[0]
|
|
85
|
-
@start.type = "Fußweg" # route[2]
|
|
86
|
-
@start.end_time = DateTime.parse(summary_time.split("-").first.gsub(".13", ".2013"))
|
|
87
|
-
@start.start_time = @start.end_time - route[1].to_i.minutes
|
|
88
|
-
@start.target = route[3]
|
|
89
|
-
|
|
90
|
-
@target = RoutePart.new
|
|
91
|
-
@target.type = "Fußweg"
|
|
92
|
-
@target.target = route.last
|
|
93
|
-
if summary_time.split("-").last.strip.length != 5
|
|
94
|
-
# Date is included in the string
|
|
95
|
-
@target.end_time = DateTime.parse(summary_time.split("-").last.gsub(".13", ".2013"))
|
|
96
|
-
else
|
|
97
|
-
# no date given, use start date
|
|
98
|
-
@target.end_time = DateTime.parse("#{@start.start_time.to_date} #{summary_time.split("-").last}")
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
@target.end_time += route[route.length-3].to_i.minutes
|
|
102
|
-
|
|
103
|
-
@date = (@start.start_time.to_date) # otherwise all dates will be "today"
|
|
104
|
-
@parts = [@start]
|
|
105
|
-
create_parts 3, route
|
|
106
|
-
@parts << @target
|
|
107
|
-
end
|
|
108
|
-
|
|
109
97
|
# Create all general parts.
|
|
110
98
|
# Set @parts, @target and @date first!
|
|
111
99
|
def create_parts start_index, route
|
|
100
|
+
@parts = [@start]
|
|
112
101
|
i = start_index
|
|
102
|
+
done_anything = false
|
|
113
103
|
while i < route.length do
|
|
114
104
|
if route[i..i+4].count != 5 || route[i..i+4].include?(nil)
|
|
115
105
|
break
|
|
116
106
|
end
|
|
117
107
|
|
|
108
|
+
done_anything = true
|
|
118
109
|
part = RoutePart.new
|
|
119
|
-
part.start = route[i]
|
|
110
|
+
part.start = Station.new({"value" => route[i], :load => :station, :do_load => @do_load})
|
|
120
111
|
@parts.last.target = part.start
|
|
121
112
|
part.type = route[i+2].squeeze
|
|
122
113
|
|
|
123
114
|
begin
|
|
124
115
|
part.start_time = DateTime.parse(@date.to_s + route[i+1])
|
|
125
116
|
part.end_time = DateTime.parse(@date.to_s + route[i+3])
|
|
126
|
-
part.target = route[i+4]
|
|
117
|
+
part.target = Station.new({"value" => route[i+4], :load => :station, :do_load => @do_load})
|
|
127
118
|
i += 4
|
|
128
119
|
rescue ArgumentError
|
|
129
120
|
# occures if there is a "Fußweg" in between
|
|
130
121
|
part.start_time = @parts.last.end_time
|
|
131
122
|
part.end_time = part.start_time + route[i+1].to_i.minutes
|
|
132
|
-
part.target = route[i+3]
|
|
123
|
+
part.target = Station.new({"value" => route[i+3], :load => :foot, :do_load => @do_load})
|
|
133
124
|
i += 3
|
|
134
125
|
end
|
|
135
126
|
|
|
@@ -142,6 +133,11 @@ module Bahn
|
|
|
142
133
|
# we don't want to show Fußwege from and to the same station
|
|
143
134
|
@parts << part unless part.start == part.target
|
|
144
135
|
end
|
|
136
|
+
|
|
137
|
+
unless done_anything
|
|
138
|
+
@target.start_time = @parts.last.end_time
|
|
139
|
+
@target.start = @parts.last.start
|
|
140
|
+
end
|
|
145
141
|
end
|
|
146
142
|
end
|
|
147
143
|
end
|
data/lib/bahn/bahn_routepart.rb
CHANGED
|
@@ -7,12 +7,26 @@ module Bahn
|
|
|
7
7
|
# Return a nicely formatted route
|
|
8
8
|
# Raises errors if not everything is set properly
|
|
9
9
|
def to_s
|
|
10
|
-
"Am #{start_time.to_date} von #{start_time.
|
|
10
|
+
"Am #{start_time.to_date} von #{start_time.to_formatted_s :time} bis #{end_time.to_date.to_s + ' ' if end_time.to_date != start_time.to_date}#{end_time.to_formatted_s :time} : #{start} nach #{target} via #{type}"
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
# Set the type, e.g. Fußweg
|
|
14
14
|
def type= val
|
|
15
15
|
@type = val.squeeze(" ")
|
|
16
16
|
end
|
|
17
|
+
|
|
18
|
+
def transport_type
|
|
19
|
+
short_type = self.type.split.first.downcase
|
|
20
|
+
if ["str", "u", "s", "re", "erb", "ic", "ice"].include? short_type
|
|
21
|
+
return :train
|
|
22
|
+
elsif ["bus", "ne"].include? short_type
|
|
23
|
+
return :bus
|
|
24
|
+
elsif "Fußweg" == short_type
|
|
25
|
+
return :foot
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# nothing else works
|
|
29
|
+
self.type
|
|
30
|
+
end
|
|
17
31
|
end
|
|
18
32
|
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module Bahn
|
|
2
|
+
class Station
|
|
3
|
+
attr_accessor :lat, :lon, :name
|
|
4
|
+
def initialize json={}
|
|
5
|
+
self.name = json["value"] unless json["value"].nil?
|
|
6
|
+
|
|
7
|
+
if json[:do_load]
|
|
8
|
+
station = Agent.new.find_station(name) if json[:load] == :station
|
|
9
|
+
station = Agent.new.find_address(name) if json[:load] == :foot
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
if station.nil?
|
|
13
|
+
self.lat = json["ycoord"].insert(-7, ".") unless json["ycoord"].nil?
|
|
14
|
+
self.lon = json["xcoord"].insert(-7, ".") unless json["xcoord"].nil?
|
|
15
|
+
else
|
|
16
|
+
self.lat = station.lat
|
|
17
|
+
self.lon = station.lon
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def to_s
|
|
22
|
+
"#{self.name} (#{self.lat},#{self.lon})"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def == other
|
|
26
|
+
return false if other.nil?
|
|
27
|
+
other.name == self.name
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
data/lib/bahn.rb
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
require 'rubygems'
|
|
2
2
|
require 'mechanize'
|
|
3
3
|
require 'active_support/all'
|
|
4
|
-
require 'action_view'
|
|
5
4
|
require 'json'
|
|
6
5
|
|
|
7
|
-
|
|
8
6
|
require 'bahn/bahn_routepart'
|
|
9
7
|
require 'bahn/bahn_route'
|
|
10
|
-
require 'bahn/
|
|
8
|
+
require 'bahn/bahn_station'
|
|
9
|
+
require 'bahn/bahn_agent'
|
|
10
|
+
|
|
11
|
+
module Bahn
|
|
12
|
+
VERSION = "2.0.0"
|
|
13
|
+
end
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: bahn.rb
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
hash:
|
|
4
|
+
hash: 15
|
|
5
5
|
prerelease:
|
|
6
6
|
segments:
|
|
7
|
-
-
|
|
7
|
+
- 2
|
|
8
8
|
- 0
|
|
9
9
|
- 0
|
|
10
|
-
version:
|
|
10
|
+
version: 2.0.0
|
|
11
11
|
platform: ruby
|
|
12
12
|
authors:
|
|
13
13
|
- Simon Woker
|
|
@@ -15,7 +15,7 @@ autorequire:
|
|
|
15
15
|
bindir: bin
|
|
16
16
|
cert_chain: []
|
|
17
17
|
|
|
18
|
-
date: 2013-02-
|
|
18
|
+
date: 2013-02-20 00:00:00 Z
|
|
19
19
|
dependencies:
|
|
20
20
|
- !ruby/object:Gem::Dependency
|
|
21
21
|
version_requirements: &id001 !ruby/object:Gem::Requirement
|
|
@@ -86,10 +86,11 @@ files:
|
|
|
86
86
|
- lib/bahn/bahn_agent.rb
|
|
87
87
|
- lib/bahn/bahn_route.rb
|
|
88
88
|
- lib/bahn/bahn_routepart.rb
|
|
89
|
-
- lib/bahn/
|
|
89
|
+
- lib/bahn/bahn_station.rb
|
|
90
90
|
- lib/bahn.rb
|
|
91
91
|
- LICENSE
|
|
92
|
-
|
|
92
|
+
- README.md
|
|
93
|
+
homepage: https://github.com/swoker/bahn.rb
|
|
93
94
|
licenses: []
|
|
94
95
|
|
|
95
96
|
post_install_message:
|
data/lib/bahn/version.rb
DELETED