reittiopas 0.0.2 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
File without changes
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --colour
2
+ --format progress
@@ -0,0 +1,9 @@
1
+ lib/reittiopas.rb cced8096a3f0992a8d81ae358594e52a6149fff2
2
+ lib/reittiopas/reittiopas.rb 5019a3c332476f0e31f7416adfef3944c74ac649
3
+ lib/reittiopas/location.rb ddaf1913f5f6cc3267c5b97295c8daa3dc5375ac
4
+ lib/reittiopas/utils.rb 67f54e983f78e319fb239d173359fedf7d5187f6
5
+ lib/reittiopas/routing.rb 5833a35b3953e8f1d88e4ef48e6df43a4c72be47
6
+ lib/reittiopas/http.rb e5fccc0834481a6b2a1d732e2f7fa9007a291247
7
+ lib/reittiopas/geocoding.rb 41aacb43af4a7b178571646e7c4c2413dab250eb
8
+ lib/reittiopas/exceptions.rb c3d2abd5037e5971a29bc760b14171f8bba8c0b0
9
+ lib/reittiopas/coordinates.rb e4114495a73f43c51d040f3147f963fe28fcd1b6
@@ -0,0 +1,4 @@
1
+ {
2
+ : module[
3
+ "
4
+ class["Reittiopas"Reittiopas::HTTP"Nokogiri::XML::Element" Hash"Reittiopas::Routing::Route"!Reittiopas::Routing::Section"Reittiopas::Routing::Point"%Reittiopas::Routing::MapLocation"Reittiopas::Routing::Stop"%Reittiopas::Routing::SectionTime"!Reittiopas::Routing::Arrival"#Reittiopas::Routing::Departure"Reittiopas::Routing::Part"Reittiopas::Routing::Walk"Reittiopas::Routing::Line"Reittiopas::Location"*Reittiopas::Location::PointOfInterest"Reittiopas::Location::Stop"!Reittiopas::Location::Street"Reittiopas::AccessError"+Reittiopas::Location::Coordinates::WGS"+Reittiopas::Location::Coordinates::KKJ: root[;:
Binary file
Binary file
@@ -1,3 +1,13 @@
1
+ === 0.1.0 2012-08-12
2
+
3
+ * Routing support from Matti Paksula
4
+ * Updated the project to use Rspec 2
5
+ * Use YARD for docs instead of Rdoc
6
+
7
+ === 0.0.2 2010-04-22
8
+
9
+ * Fixed incorrectly configured runtime dependencies.
10
+
1
11
  === 0.0.1 2010-04-05
2
12
 
3
13
  * 1 major enhancement:
@@ -1,6 +1,11 @@
1
+ .rspec
2
+ .yardoc/checksums
3
+ .yardoc/object_types
4
+ .yardoc/objects/root.dat
5
+ .yardoc/proxy_types
1
6
  History.txt
2
7
  Manifest.txt
3
- README.rdoc
8
+ README.md
4
9
  Rakefile
5
10
  lib/reittiopas.rb
6
11
  lib/reittiopas/coordinates.rb
@@ -9,15 +14,19 @@ lib/reittiopas/geocoding.rb
9
14
  lib/reittiopas/http.rb
10
15
  lib/reittiopas/location.rb
11
16
  lib/reittiopas/reittiopas.rb
17
+ lib/reittiopas/routing.rb
12
18
  lib/reittiopas/utils.rb
13
19
  script/console
14
20
  script/destroy
15
21
  script/generate
22
+ spec/fixtures/kallion_kirjasto.xml
16
23
  spec/fixtures/key.xml
17
24
  spec/fixtures/no_access
18
25
  spec/fixtures/reverse_geocoding.xml
26
+ spec/fixtures/route_ulvilantie_19-kallion_kirjasto.xml
27
+ spec/fixtures/ulvilantie_19_helsinki.xml
28
+ spec/reittiopas_routing_spec.rb
19
29
  spec/reittiopas_spec.rb
20
- spec/spec.opts
21
30
  spec/spec_helper.rb
22
31
  tasks/rdoc.rake
23
32
  tasks/rspec.rake
@@ -0,0 +1,103 @@
1
+ # Reittiopas
2
+
3
+ * [Documentation at Github](http://raneksi.github.com/reittiopas/)
4
+ * [Specifications](http://raneksi.github.com/reittiopas/specdoc)
5
+
6
+ ## DESCRIPTION
7
+
8
+ Reittiopas is a Ruby library for accessing the [Reittiopas Developer API](http://developer.reittiopas.fi/pages/fi/reittiopas-api.php).
9
+
10
+ Requires an account to the service that can be requested through [the account request page](http://developer.reittiopas.fi/pages/fi/accountrequest.php).
11
+
12
+ ## SYNOPSIS
13
+
14
+ require 'reittiopas'
15
+ reittiopas = Reittiopas.new(:username => 'myuser', :password => 'lolcats')
16
+
17
+ #### Geocoding
18
+
19
+ Search for location by keyword _tee_.
20
+
21
+ location = reittiopas.location('tee').first
22
+ puts "#{location}, #{location.city}"
23
+ puts "http://maps.google.com/maps?q=#{URI.escape location.coordinates[:wgs]}"
24
+
25
+ => Teeripuisto, Helsinki
26
+ => http://maps.google.com/maps?q=60.2528,%2025.02051
27
+
28
+ ### Reverse geocoding
29
+
30
+ Search for a location by [KKJ coordinates](http://fi.wikipedia.org/wiki/Kartastokoordinaattij%C3%A4rjestelm%C3%A4).
31
+
32
+ location = reittiopas.location(:x => 2546445, :y => 6675512).first
33
+ puts "#{location}, #{location.city}"
34
+
35
+ => Otakaari 9, Espoo
36
+
37
+ ### Routing
38
+
39
+ Search for routes between two locations: show 3 routes and do not use metro.
40
+
41
+ from = reittiopas.locations('mannerheimintie 5').first
42
+ to = reittiopas.location('kallion kirjasto').first
43
+
44
+ routes = reittiopas.routing(from, to, {"show" => 3, "use_metro" => 0})
45
+ routes.each do |route|
46
+ puts "#{route.distance} #{route.time}"
47
+ puts "Lines: "
48
+
49
+ route.lines.each do |line|
50
+ puts "#{line.code} starts from: #{line.stops.first.code}"
51
+ end
52
+ end
53
+
54
+ Options for routing are passed to Reittiopas. See Reittiopas developer API for the possible options.
55
+
56
+
57
+ ## INSTALLATION
58
+
59
+ gem install reittiopas
60
+
61
+ or to use latest upstream:
62
+
63
+ git clone git://github.com/raneksi/reittiopas.git
64
+ cd reittiopas
65
+ rake newb
66
+ rake install_gem
67
+
68
+ ## REQUIREMENTS
69
+
70
+ * [Nokogiri](htttp://nokogiri.org)
71
+ * [Addressable](http://github.com/sporkmonger/addressable)
72
+
73
+ ## TODO
74
+
75
+ * Support for determining the closest stop within radius
76
+
77
+ ## LICENSE
78
+
79
+ (The MIT License)
80
+
81
+ Copyright (c) 2010 - 2011:
82
+
83
+ * [Raine Virta](https://github.com/raneksi)
84
+ * [Matti Paksula](https://github.com/matti)
85
+
86
+ Permission is hereby granted, free of charge, to any person obtaining
87
+ a copy of this software and associated documentation files (the
88
+ 'Software'), to deal in the Software without restriction, including
89
+ without limitation the rights to use, copy, modify, merge, publish,
90
+ distribute, sublicense, and/or sell copies of the Software, and to
91
+ permit persons to whom the Software is furnished to do so, subject to
92
+ the following conditions:
93
+
94
+ The above copyright notice and this permission notice shall be
95
+ included in all copies or substantial portions of the Software.
96
+
97
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
98
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
99
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
100
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
101
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
102
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
103
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile CHANGED
@@ -1,27 +1,33 @@
1
- require 'rubygems'
2
- gem 'hoe', '>= 2.1.0'
3
- require 'hoe'
4
- require 'fileutils'
5
-
6
- Hoe.plugin :newgem
7
-
8
- $hoe = Hoe.spec 'reittiopas' do
9
- developer 'Raine Virta', 'raine.virta@gmail.com'
10
- self.rubyforge_name = self.name
11
-
12
- %w{ addressable nokogiri }.each do |dep|
13
- self.extra_deps << [dep, '>= 0']
14
- end
15
-
16
- self.url = "http://github.com/raneksi/reittiopas"
17
- self.extra_dev_deps = [
18
- ['webmock', ">= 0.9.1"],
19
- ['rspec', ">= 0"],
20
- ['darkfish-rdoc', ">= 0"]
21
- ]
22
- self.readme_file = "README.rdoc"
23
- self.extra_rdoc_files = FileList['*.rdoc']
24
- end
25
-
26
- require 'newgem/tasks'
27
- Dir['tasks/**/*.rake'].each { |t| load t }
1
+ require 'rubygems'
2
+ gem 'hoe', '>= 2.1.0'
3
+ require 'hoe'
4
+ require 'fileutils'
5
+
6
+ Hoe.plugin :newgem
7
+ Hoe.plugin :yard
8
+
9
+ $hoe = Hoe.spec 'reittiopas' do
10
+ developer 'Raine Virta', 'raine.virta@gmail.com'
11
+ self.rubyforge_name = self.name
12
+
13
+ self.extra_deps = [
14
+ [ 'addressable', '= 2.2.8' ],
15
+ [ 'nokogiri', '>= 0']
16
+ ]
17
+
18
+ self.readme_file = "README.md"
19
+ self.urls = ["http://github.com/raneksi/reittiopas"]
20
+ self.extra_dev_deps = [
21
+ ['webmock', "= 1.8.8"],
22
+ ['rspec', "= 2.11.0"],
23
+ ['yard', ">= 0.8.2.1"],
24
+ ['hoe-yard', ">= 0"]
25
+ ]
26
+
27
+ self.yard_title = 'Reittiopas (0.1.0)'
28
+ self.yard_markup = "markdown"
29
+ self.yard_opts = ['--protected']
30
+ end
31
+
32
+ require 'newgem/tasks'
33
+ Dir['tasks/**/*.rake'].each { |t| load t }
@@ -3,6 +3,7 @@ require 'cgi'
3
3
  require 'net/http'
4
4
  require 'nokogiri'
5
5
  require 'addressable/uri'
6
+ require 'date'
6
7
 
7
8
  $:.unshift(File.dirname(__FILE__)) unless
8
9
  $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
@@ -12,12 +13,13 @@ require 'reittiopas/utils'
12
13
  require 'reittiopas/coordinates'
13
14
  require 'reittiopas/location'
14
15
  require 'reittiopas/geocoding'
16
+ require 'reittiopas/routing'
15
17
  require 'reittiopas/reittiopas'
16
18
  require 'reittiopas/http'
17
19
 
18
20
  class Reittiopas
19
21
  # The version of Reittiopas you are using.
20
- VERSION = "0.0.2"
22
+ VERSION = "0.1.0"
21
23
  end
22
24
 
23
25
  # Shorter way for Reittiopas instance creation.
@@ -19,6 +19,10 @@ class Location
19
19
  @x = opts[:x].to_i
20
20
  @y = opts[:y].to_i
21
21
  end
22
+
23
+ def to_routing_string
24
+ "#{@x},#{@y}"
25
+ end
22
26
  end
23
27
  end
24
28
  end
@@ -3,7 +3,8 @@
3
3
  #
4
4
  class Reittiopas
5
5
  include Geocoding
6
-
6
+ include Routing
7
+
7
8
  # Instantiate a Reittiopas object.
8
9
  #
9
10
  # [account] A hash containing the keys +:username+ and +:password+ with
@@ -0,0 +1,310 @@
1
+ class Reittiopas
2
+
3
+ module Routing
4
+
5
+ # Route between two Locations. Returns an array of Routes that contain all sub elements
6
+
7
+ def routing(from, to, opts)
8
+ @from = from
9
+ @to = to
10
+ @options = opts
11
+
12
+ params = { :a => @from.coordinates[:kkj].to_routing_string,
13
+ :b => @to.coordinates[:kkj].to_routing_string}.merge(@options)
14
+
15
+ xml = @http.get(params)
16
+ doc = Nokogiri::XML(xml)
17
+
18
+ routes = []
19
+
20
+ doc.search("ROUTE").each do |route|
21
+ routes << Route.parse(route)
22
+ end
23
+
24
+ return routes
25
+ end
26
+
27
+
28
+ class Route
29
+
30
+ attr_reader :time, :distance, :parts, :walks, :lines
31
+
32
+ def initialize(opts)
33
+ @time = opts[:time].to_f if opts[:time]
34
+ @distance = opts[:distance].to_f if opts[:distance]
35
+
36
+ @parts, @walks, @lines = opts[:parts], opts[:walks], opts[:lines]
37
+ end
38
+
39
+
40
+ # Parse the route and sub elements
41
+ def self.parse(xml)
42
+ length_element = xml.search("LENGTH").first
43
+
44
+ time = length_element.get_attr_value "time"
45
+ dist = length_element.get_attr_value "dist"
46
+
47
+ parts, walks, lines = [], [], []
48
+
49
+ xml.elements.each do |e|
50
+ next if e.name == "LENGTH"
51
+ case e.name
52
+ when "POINT"
53
+ parts << Point.parse(e)
54
+ when "WALK"
55
+ walk = Walk.parse(e)
56
+ parts << walk
57
+ walks << walk
58
+ when "LINE"
59
+ line = Line.parse(e)
60
+ parts << line
61
+ lines << line
62
+ end
63
+
64
+ end
65
+
66
+ new(:time => time,
67
+ :distance => dist,
68
+ :parts => parts,
69
+ :walks => walks,
70
+ :lines => lines)
71
+
72
+ end
73
+
74
+ end
75
+
76
+
77
+ # Points, MapLocations and Stops are Sections
78
+ class Section
79
+ attr_reader :x, :y, :arrival, :departure
80
+
81
+ def initialize(opts)
82
+ @x = opts[:x].to_f if opts[:x]
83
+ @y = opts[:y].to_f if opts[:y]
84
+ @arrival = opts[:arrival]
85
+ @departure = opts[:departure]
86
+ end
87
+
88
+ def self.parse(xml)
89
+ x = xml.get_attr_value "x"
90
+ y = xml.get_attr_value "y"
91
+
92
+ arrival_element = xml.search("ARRIVAL").first
93
+ departure_element = xml.search("DEPARTURE").first
94
+
95
+ arrival = Arrival.parse arrival_element
96
+ departure = Departure.parse departure_element
97
+
98
+ { :x => x,
99
+ :y => y,
100
+ :arrival => arrival,
101
+ :departure => departure }
102
+ end
103
+
104
+ end
105
+
106
+ class Point < Section
107
+
108
+ attr_reader :uid
109
+
110
+ def initialize(opts)
111
+ super
112
+ @uid = opts[:uid]
113
+ end
114
+
115
+ def self.parse(xml)
116
+ opts = super
117
+
118
+ uid = xml.get_attr_value "uid"
119
+
120
+ opts.merge!( :uid => uid )
121
+ new(opts)
122
+ end
123
+ end
124
+
125
+ class MapLocation < Section
126
+
127
+ attr_reader :location_type, :name
128
+
129
+ def initialize(opts)
130
+ super
131
+ @location_type = opts[:location_type].to_i if opts[:location_type]
132
+ @name = opts[:name]
133
+ end
134
+
135
+ def self.parse(xml)
136
+ opts = super
137
+ location_type = xml.get_attr_value "type"
138
+
139
+ name_elements = xml.search("NAME")
140
+ name = name_elements.first.get_attr_value "val" if name_elements.first
141
+
142
+ opts.merge!(:location_type => location_type,
143
+ :name => name)
144
+
145
+ new(opts)
146
+ end
147
+ end
148
+
149
+ class Stop < Section
150
+
151
+ attr_reader :code, :stop_id,
152
+ :names
153
+
154
+ def initialize(opts)
155
+ super
156
+ @code = opts[:code]
157
+ @stop_id = opts[:stop_id]
158
+ @names = opts[:names]
159
+ end
160
+
161
+ def self.parse(xml)
162
+ opts = super
163
+
164
+ code = xml.get_attr_value "code"
165
+ stop_id = xml.get_attr_value "id"
166
+
167
+ name_elements = xml.search("NAME")
168
+
169
+ names = {}
170
+ name_elements.each do |e|
171
+ lang = e.get_attr_value "lang"
172
+ val = e.get_attr_value "val"
173
+
174
+ names[lang] = val
175
+ end
176
+
177
+ opts.merge!(:code => code,
178
+ :stop_id => stop_id,
179
+ :names => names)
180
+ new(opts)
181
+ end
182
+
183
+ end
184
+
185
+ # Each Section has Arrival and Departure times (and seems that those are always the same)
186
+
187
+ class SectionTime
188
+
189
+ attr_reader :date_time
190
+
191
+ def initialize(opts)
192
+ @date_time = DateTime.parse("#{opts[:date]} #{opts[:time]}")
193
+ end
194
+
195
+ def self.parse(xml)
196
+ date = xml.get_attr_value "date"
197
+ time = xml.get_attr_value "time"
198
+
199
+ new(:date => date,
200
+ :time => time)
201
+ end
202
+ end
203
+
204
+ class Arrival < SectionTime ; end
205
+
206
+ class Departure < SectionTime ; end
207
+
208
+
209
+ # Part represents Walks and Lines.
210
+ class Part
211
+
212
+ attr_reader :time, :distance,
213
+ :sections, :map_locations, :points, :stops
214
+
215
+ def initialize(opts)
216
+ @time = opts[:time].to_f if opts[:time]
217
+ @distance = opts[:distance].to_f if opts[:time]
218
+ @sections, @map_locations, @points, @stops = opts[:sections], opts[:map_locations], opts[:points], opts[:stops]
219
+ end
220
+
221
+ def self.parse(xml)
222
+ length_element = xml.search("LENGTH").first
223
+
224
+ time = length_element.get_attr_value "time"
225
+ distance = length_element.get_attr_value "dist"
226
+
227
+ sections, map_locations, points, stops = [], [], [], []
228
+
229
+ xml.elements.each do |e|
230
+ next if e.name == "LENGTH"
231
+
232
+ case e.name
233
+ when "POINT"
234
+ point = Point.parse(e)
235
+ sections << point
236
+ points << point
237
+ when "MAPLOC"
238
+ map_location = MapLocation.parse(e)
239
+ sections << map_location
240
+ map_locations << map_location
241
+ when "STOP"
242
+ stop = Stop.parse(e)
243
+ sections << stop
244
+ stops << stop
245
+ end
246
+ end
247
+
248
+ { :time => time,
249
+ :distance => distance,
250
+ :sections => sections,
251
+ :map_locations => map_locations,
252
+ :points => points,
253
+ :stops => stops }
254
+ end
255
+
256
+ end
257
+
258
+ class Walk < Part
259
+
260
+ def self.parse(xml)
261
+ opts = super
262
+
263
+ new opts
264
+ end
265
+ end
266
+
267
+ class Line < Part
268
+ attr_reader :line_id, :code, :line_type, :mobility
269
+
270
+ def initialize(opts)
271
+ super
272
+
273
+ @line_id = opts[:line_id]
274
+ @code = opts[:code]
275
+ @line_type = opts[:line_type].to_i if opts[:line_type]
276
+ @mobility = opts[:mobility].to_i if opts[:mobility]
277
+
278
+ @stops = opts[:stops] || []
279
+ end
280
+
281
+ def self.parse(xml)
282
+ opts = super
283
+
284
+ line_id = xml.get_attr_value "id"
285
+ code = xml.get_attr_value "code"
286
+ line_type = xml.get_attr_value "type"
287
+ mobility = xml.get_attr_value "mobility"
288
+
289
+ stops = []
290
+
291
+ opts[:sections].each do |section|
292
+ stops << section if section.is_a? Stop
293
+ end
294
+
295
+ opts.merge!(:line_id => line_id,
296
+ :code => code,
297
+ :line_type => line_type,
298
+ :mobility => mobility,
299
+ :stops => stops)
300
+
301
+ new(opts)
302
+ end
303
+ end
304
+
305
+
306
+ end
307
+
308
+
309
+
310
+ end