reittiopas 0.0.2 → 0.1.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.
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