reittiopas 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +4 -0
- data/Manifest.txt +21 -0
- data/README.rdoc +58 -0
- data/Rakefile +34 -0
- data/deps.rip +1 -0
- data/lib/reittiopas.rb +28 -0
- data/lib/reittiopas/coordinates.rb +25 -0
- data/lib/reittiopas/geocoding.rb +53 -0
- data/lib/reittiopas/http.rb +40 -0
- data/lib/reittiopas/location.rb +87 -0
- data/lib/reittiopas/reittiopas.rb +15 -0
- data/lib/reittiopas/utils.rb +11 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/spec/fixtures/key.xml +22 -0
- data/spec/fixtures/reverse_geocoding.xml +5 -0
- data/spec/reittiopas_spec.rb +245 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +19 -0
- data/tasks/rspec.rake +38 -0
- metadata +114 -0
data/History.txt
ADDED
data/Manifest.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
History.txt
|
2
|
+
Manifest.txt
|
3
|
+
README.rdoc
|
4
|
+
Rakefile
|
5
|
+
deps.rip
|
6
|
+
lib/reittiopas.rb
|
7
|
+
lib/reittiopas/coordinates.rb
|
8
|
+
lib/reittiopas/geocoding.rb
|
9
|
+
lib/reittiopas/http.rb
|
10
|
+
lib/reittiopas/location.rb
|
11
|
+
lib/reittiopas/reittiopas.rb
|
12
|
+
lib/reittiopas/utils.rb
|
13
|
+
script/console
|
14
|
+
script/destroy
|
15
|
+
script/generate
|
16
|
+
spec/fixtures/key.xml
|
17
|
+
spec/fixtures/reverse_geocoding.xml
|
18
|
+
spec/reittiopas_spec.rb
|
19
|
+
spec/spec.opts
|
20
|
+
spec/spec_helper.rb
|
21
|
+
tasks/rspec.rake
|
data/README.rdoc
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
= Reittiopas
|
2
|
+
|
3
|
+
* {Documentation at Github}[http://raneksi.github.com/reittiopas/]
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
Reittiopas is a Ruby library for accessing the {Reittiopas Developer API}[http://developer.reittiopas.fi/pages/fi/reittiopas-api.php].
|
8
|
+
|
9
|
+
Requires an account to the service that can be requested through {the account request page}[http://developer.reittiopas.fi/pages/fi/accountrequest.php].
|
10
|
+
|
11
|
+
== SYNOPSIS:
|
12
|
+
require 'reittiopas'
|
13
|
+
reittiopas = Reittiopas.new(:username => 'myuser', :password => 'lolcats')
|
14
|
+
|
15
|
+
=== Geocoding
|
16
|
+
Search for location by keyword _tee_.
|
17
|
+
location = reittiopas.location('tee').first
|
18
|
+
puts "#{location}, #{location.city}"
|
19
|
+
puts "http://maps.google.com/maps?q=#{URI.escape location.coordinates[:wgs]}"
|
20
|
+
Teeripuisto, Helsinki
|
21
|
+
|
22
|
+
http://maps.google.com/maps?q=60.2528,%2025.02051
|
23
|
+
|
24
|
+
=== Reverse geocoding
|
25
|
+
Search for a location by KKJ[http://fi.wikipedia.org/wiki/Kartastokoordinaattij%C3%A4rjestelm%C3%A4] coordinates.
|
26
|
+
location = reittiopas.location(:x => 2546445, :y => 6675512).first
|
27
|
+
puts "#{location}, #{location.city}"
|
28
|
+
Otakaari 9, Espoo
|
29
|
+
|
30
|
+
== REQUIREMENTS:
|
31
|
+
|
32
|
+
* Nokogiri[http://nokogiri.org/]
|
33
|
+
* Addressable[http://github.com/sporkmonger/addressable]
|
34
|
+
|
35
|
+
== LICENSE:
|
36
|
+
|
37
|
+
(The MIT License)
|
38
|
+
|
39
|
+
Copyright (c) 2010 Raine Virta
|
40
|
+
|
41
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
42
|
+
a copy of this software and associated documentation files (the
|
43
|
+
'Software'), to deal in the Software without restriction, including
|
44
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
45
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
46
|
+
permit persons to whom the Software is furnished to do so, subject to
|
47
|
+
the following conditions:
|
48
|
+
|
49
|
+
The above copyright notice and this permission notice shall be
|
50
|
+
included in all copies or substantial portions of the Software.
|
51
|
+
|
52
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
53
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
54
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
55
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
56
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
57
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
58
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
gem 'hoe', '>= 2.1.0'
|
3
|
+
require 'hoe'
|
4
|
+
require 'fileutils'
|
5
|
+
require './lib/reittiopas'
|
6
|
+
|
7
|
+
Hoe.plugin :newgem
|
8
|
+
|
9
|
+
$hoe = Hoe.spec 'reittiopas' do
|
10
|
+
developer 'Raine Virta', 'raine.virta@gmail.com'
|
11
|
+
self.rubyforge_name = self.name
|
12
|
+
|
13
|
+
%w{ addressable nokogiri }.each do |dep|
|
14
|
+
self.extra_dev_deps << [dep, '>= 0']
|
15
|
+
end
|
16
|
+
|
17
|
+
self.url = "http://github.com/raneksi/reittiopas"
|
18
|
+
self.extra_dev_deps = [['webmock', ">= 0"]]
|
19
|
+
self.readme_file = "README.rdoc"
|
20
|
+
self.extra_rdoc_files = FileList['*.rdoc']
|
21
|
+
end
|
22
|
+
|
23
|
+
require 'newgem/tasks'
|
24
|
+
Dir['tasks/**/*.rake'].each { |t| load t }
|
25
|
+
|
26
|
+
# remove_task :default
|
27
|
+
# task :default => [:spec, :features]
|
28
|
+
|
29
|
+
require 'gokdok'
|
30
|
+
Gokdok::Dokker.new do |gd|
|
31
|
+
gd.repo_url = "git@github.com:raneksi/reittiopas.git"
|
32
|
+
gd.rdoc_task = :docs
|
33
|
+
gd.doc_home = 'doc'
|
34
|
+
end
|
data/deps.rip
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
http://github.com/sporkmonger/addressable.git
|
data/lib/reittiopas.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__)) unless
|
2
|
+
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'uri'
|
6
|
+
require 'cgi'
|
7
|
+
require 'net/http'
|
8
|
+
require 'nokogiri'
|
9
|
+
require 'addressable/uri'
|
10
|
+
|
11
|
+
require 'reittiopas/utils'
|
12
|
+
require 'reittiopas/coordinates'
|
13
|
+
require 'reittiopas/location'
|
14
|
+
require 'reittiopas/geocoding'
|
15
|
+
require 'reittiopas/reittiopas'
|
16
|
+
require 'reittiopas/http'
|
17
|
+
|
18
|
+
class Reittiopas
|
19
|
+
# The version of Reittiopas you are using.
|
20
|
+
VERSION = "0.0.1"
|
21
|
+
end
|
22
|
+
|
23
|
+
# Shorter way for Reittiopas instance creation.
|
24
|
+
# In actuality, this doesn't make much sense since it just hides
|
25
|
+
# the +new+ method. FIXME
|
26
|
+
def Reittiopas(account)
|
27
|
+
return Reittiopas.new(account)
|
28
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class Reittiopas
|
2
|
+
class Location
|
3
|
+
module Coordinates # :nodoc:
|
4
|
+
class WGS
|
5
|
+
attr_accessor :latitude, :longitude
|
6
|
+
def initialize(opts)
|
7
|
+
@latitude = opts[:lat].to_f
|
8
|
+
@longitude = opts[:lon].to_f
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_s
|
12
|
+
[@latitude, @longitude].join(', ')
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class KKJ
|
17
|
+
attr_accessor :x, :y
|
18
|
+
def initialize(opts)
|
19
|
+
@x = opts[:x].to_i
|
20
|
+
@y = opts[:y].to_i
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
class Reittiopas
|
2
|
+
|
3
|
+
# Module implementing the geocoding features of the Reittiopas API
|
4
|
+
# documented at http://developer.reittiopas.fi/pages/fi/http-get-interface.php
|
5
|
+
module Geocoding
|
6
|
+
|
7
|
+
# Send a geocode location query to the API.
|
8
|
+
# Both geocoding, and reverse geocoding data is accessed through this method.
|
9
|
+
#
|
10
|
+
# Returns results as an array containing Reittiopas::Location objects.
|
11
|
+
#
|
12
|
+
# === Examples:
|
13
|
+
# * Search for location by keyword _tee_.
|
14
|
+
# reittiopas.location('tee')
|
15
|
+
#
|
16
|
+
# * Search for location by KKJ coordinates x: _2546445_, y: _6675512_.
|
17
|
+
# reittiopas.location(:x => 2546445, :y => 6675512)
|
18
|
+
#
|
19
|
+
def location(opts)
|
20
|
+
params = if opts.is_a? String
|
21
|
+
{:key => opts}
|
22
|
+
elsif opts.is_a? Hash
|
23
|
+
opts
|
24
|
+
end
|
25
|
+
|
26
|
+
parse @http.get(params), opts
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
# Parse XML received from a geocoding API query.
|
31
|
+
def parse(xml, opts)
|
32
|
+
doc = Nokogiri::XML(xml)
|
33
|
+
|
34
|
+
locations = doc.search('LOC').map do |loc|
|
35
|
+
Reittiopas::Location.parse(loc)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Add KKJ coordinates from REVERSE tag to each Location returned
|
39
|
+
# in case it was a reverse geocoding query
|
40
|
+
if opts.is_a? Hash
|
41
|
+
reverse = doc.search('REVERSE').last
|
42
|
+
x = reverse.get_attr_value('x').to_i
|
43
|
+
y = reverse.get_attr_value('y').to_i
|
44
|
+
|
45
|
+
locations.each do |loc|
|
46
|
+
loc.coordinates = { :kkj => Reittiopas::Location::Coordinates::KKJ.new(:x => x, :y => y) }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
return locations
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
class Reittiopas
|
2
|
+
|
3
|
+
# Reittiopas::HTTP is initialized with account details upon initialization
|
4
|
+
# of a Reittiopas object.
|
5
|
+
#
|
6
|
+
# Since Reittiopas API is to be queried using
|
7
|
+
# GET requests with appropriate query parameters, Reittiopas::HTTP exists
|
8
|
+
# to simplify the process by offering a +get+ method that accepts a hash
|
9
|
+
# containing the query parameters as an argument.
|
10
|
+
#
|
11
|
+
class HTTP
|
12
|
+
# Base URI for the Reittiopas API service.
|
13
|
+
API_BASE_URI = "http://api.reittiopas.fi/public-ytv/fi/api/"
|
14
|
+
|
15
|
+
# Addressable::URI instance of the API URI with account details set as
|
16
|
+
# query parameters.
|
17
|
+
attr_reader :api_uri
|
18
|
+
|
19
|
+
# Create a new Reittiopas::HTTP object.
|
20
|
+
#
|
21
|
+
# +account+ should be a hash containing +:username+ and +:password+.
|
22
|
+
def initialize(account)
|
23
|
+
@api_uri = Addressable::URI.parse(API_BASE_URI)
|
24
|
+
@api_uri.query_values = {:user => account[:username], :pass => account[:password]}
|
25
|
+
end
|
26
|
+
|
27
|
+
# Send a GET request to the API with account details and +opts+ as query
|
28
|
+
# parameters.
|
29
|
+
#
|
30
|
+
# * +opts+ — A hash containing query parameters. Values are automatically
|
31
|
+
# encoded by Addressable::URI.
|
32
|
+
def get(opts)
|
33
|
+
raise ArgumentError if opts.empty?
|
34
|
+
uri = @api_uri.dup
|
35
|
+
opts.merge!(opts){ |k,ov| ov.to_s } # Coordinates to string
|
36
|
+
uri.query_values = uri.query_values.merge(opts)
|
37
|
+
return Net::HTTP.get(uri)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
class Reittiopas
|
2
|
+
|
3
|
+
# This class represents a Location.
|
4
|
+
class Location
|
5
|
+
|
6
|
+
# Get the name of the location.
|
7
|
+
attr_accessor :name
|
8
|
+
|
9
|
+
# Get the city of the location.
|
10
|
+
attr_accessor :city
|
11
|
+
|
12
|
+
# Get the type of the location.
|
13
|
+
attr_accessor :type
|
14
|
+
|
15
|
+
# Get coordinates of the location as a Hash containing Coordinates objects.
|
16
|
+
attr_accessor :coordinates
|
17
|
+
|
18
|
+
# Get the street number of the location.
|
19
|
+
attr_accessor :number
|
20
|
+
|
21
|
+
# Create a Location object from Nokogiri::XML::Element object containing
|
22
|
+
# location data.
|
23
|
+
def self.parse(xml)
|
24
|
+
attr = xml.attributes
|
25
|
+
|
26
|
+
category = xml.get_attr_value('category')
|
27
|
+
|
28
|
+
loc = case category
|
29
|
+
when "street" then Street.new
|
30
|
+
when "stop" then Stop.new
|
31
|
+
when "poi" then PointOfInterest.new
|
32
|
+
else Location.new
|
33
|
+
end
|
34
|
+
|
35
|
+
loc.name = xml.get_attr_value 'name1'
|
36
|
+
loc.city = xml.get_attr_value 'city'
|
37
|
+
type = xml.get_attr_value 'type'
|
38
|
+
code = xml.get_attr_value 'code'
|
39
|
+
number = xml.get_attr_value 'number'
|
40
|
+
address = xml.get_attr_value 'address'
|
41
|
+
|
42
|
+
loc.type = type.to_i if type
|
43
|
+
loc.code = code.to_i if code
|
44
|
+
loc.number = number.to_i if number
|
45
|
+
loc.address = address if address
|
46
|
+
|
47
|
+
coordinates = {}
|
48
|
+
|
49
|
+
if attr["x"] && attr["y"]
|
50
|
+
coordinates[:kkj] = Coordinates::KKJ.new(Hash[*%w(x y).map { |e| [e.to_sym, attr[e].value.to_i] }.flatten])
|
51
|
+
end
|
52
|
+
|
53
|
+
if attr["lat"] && attr["lon"]
|
54
|
+
coordinates[:wgs] = Coordinates::WGS.new(Hash[*%w(lat lon).map { |e| [e.to_sym, attr[e].value.to_f] }.flatten])
|
55
|
+
end
|
56
|
+
|
57
|
+
loc.coordinates = coordinates unless coordinates.empty?
|
58
|
+
|
59
|
+
return loc
|
60
|
+
end
|
61
|
+
|
62
|
+
# Get the name and street number (if applicable) of the location.
|
63
|
+
def to_s
|
64
|
+
"#{name} #{number}".strip
|
65
|
+
end
|
66
|
+
|
67
|
+
class PointOfInterest < Location
|
68
|
+
# Get the code of the point of interest location.
|
69
|
+
attr_accessor :code
|
70
|
+
end
|
71
|
+
|
72
|
+
class Stop < Location
|
73
|
+
# Get the address of the bus stop.
|
74
|
+
#
|
75
|
+
# To follow the API's response format, only bus stops have an address. FIXME?
|
76
|
+
attr_accessor :address
|
77
|
+
|
78
|
+
# Get the code of the bus stop.
|
79
|
+
attr_accessor :code
|
80
|
+
end
|
81
|
+
|
82
|
+
class Street < Location
|
83
|
+
# Get the street number of the location.
|
84
|
+
attr_accessor :number
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# Reittiopas is a Ruby library for accessing the
|
2
|
+
# {Reittiopas Developer API}[http://developer.reittiopas.fi/pages/fi/reittiopas-api.php].
|
3
|
+
#
|
4
|
+
class Reittiopas
|
5
|
+
include Geocoding
|
6
|
+
|
7
|
+
# Instantiate a Reittiopas object.
|
8
|
+
#
|
9
|
+
# +account+ should be a hash containing +:username+ and +:password+.
|
10
|
+
#
|
11
|
+
# Reittiopas.new(:username => 'exampleuser', :password => 'lolcat')
|
12
|
+
def initialize(account)
|
13
|
+
@http = Reittiopas::HTTP.new(account)
|
14
|
+
end
|
15
|
+
end
|
data/script/console
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# File: script/console
|
3
|
+
irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
|
4
|
+
|
5
|
+
libs = " -r irb/completion"
|
6
|
+
# Perhaps use a console_lib to store any extra methods I may want available in the cosole
|
7
|
+
# libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
|
8
|
+
libs << " -r #{File.dirname(__FILE__) + '/../lib/reittiopas.rb'}"
|
9
|
+
puts "Loading reittiopas gem"
|
10
|
+
exec "#{irb} #{libs} --simple-prompt"
|
data/script/destroy
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/destroy'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Destroy.new.run(ARGV)
|
data/script/generate
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/generate'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Generate.new.run(ARGV)
|
@@ -0,0 +1,22 @@
|
|
1
|
+
<?xml version="1.0" encoding="ISO-8859-1" ?><MTRXML version="1.0">
|
2
|
+
<GEOCODE key="tee">
|
3
|
+
<LOC name1="Teeripuisto" number="" city="Helsinki" code="1700" address="" type="3" category="poi" x="2556686" y="6682815" lon="25.02051" lat="60.2528" />
|
4
|
+
<LOC name1="Teemuntie" number="" city="Helsinki" code="" address="" type="900" category="street" x="2558052" y="6685202" lon="25.04586" lat="60.27403" />
|
5
|
+
<LOC name1="Teerenpelinpolku" number="" city="Helsinki" code="" address="" type="900" category="street" x="2556598" y="6682627" lon="25.01887" lat="60.25113" />
|
6
|
+
<LOC name1="Teerentie" number="" city="Kirkkonummi" code="" address="" type="900" category="street" x="2524975" y="6686648" lon="24.44833" lat="60.29037" />
|
7
|
+
<LOC name1="Teerikuja" number="" city="Vantaa" code="" address="" type="900" category="street" x="2559103" y="6693697" lon="25.06733" lat="60.35011" />
|
8
|
+
<LOC name1="Teerikukonkuja" number="" city="Helsinki" code="" address="" type="900" category="street" x="2556898" y="6683026" lon="25.0244" lat="60.25466" />
|
9
|
+
<LOC name1="Teerikukontie" number="" city="Helsinki" code="" address="" type="900" category="street" x="2556907" y="6682892" lon="25.02453" lat="60.25346" />
|
10
|
+
<LOC name1="Teerimäentie" number="" city="Kerava" code="" address="" type="900" category="street" x="2560257" y="6698983" lon="25.08981" lat="60.39737" />
|
11
|
+
<LOC name1="Teerimäentie" number="" city="Vantaa" code="" address="" type="900" category="street" x="2562514" y="6686983" lon="25.12703" lat="60.28935" />
|
12
|
+
<LOC name1="Teeripolku" number="" city="Vantaa" code="" address="" type="900" category="street" x="2559133" y="6693811" lon="25.06791" lat="60.35113" />
|
13
|
+
<LOC name1="Teeririnne" number="" city="Vantaa" code="" address="" type="900" category="street" x="2559169" y="6693364" lon="25.06843" lat="60.34711" />
|
14
|
+
<LOC name1="Teerisuonkuja" number="" city="Helsinki" code="" address="" type="900" category="street" x="2556995" y="6682667" lon="25.02605" lat="60.25143" />
|
15
|
+
<LOC name1="Teerisuontie" number="" city="Helsinki" code="" address="" type="900" category="street" x="2557034" y="6682586" lon="25.02673" lat="60.2507" />
|
16
|
+
<LOC name1="Teeritie" number="" city="Vantaa" code="" address="" type="900" category="street" x="2559070" y="6693600" lon="25.06671" lat="60.34924" />
|
17
|
+
<LOC name1="Teekkarikylä" number="" city="Espoo" code="2222208" address="Otakaari" type="10" category="stop" x="2546445" y="6675512" lon="24.83393" lat="60.18855" />
|
18
|
+
<LOC name1="Teerisuonkuja" number="" city="Helsinki" code="1382186" address="Teerisuontie" type="10" category="stop" x="2556964" y="6682609" lon="25.02547" lat="60.25091" />
|
19
|
+
<LOC name1="Teerisuontie" number="" city="Helsinki" code="1382141" address="Teerisuontie" type="10" category="stop" x="2556740" y="6682861" lon="25.0215" lat="60.25321" />
|
20
|
+
<LOC name1="Teeritie" number="" city="Vantaa" code="4810204" address="Korsontie" type="10" category="stop" x="2559002" y="6694007" lon="25.06559" lat="60.35291" />
|
21
|
+
</GEOCODE>
|
22
|
+
</MTRXML>
|
@@ -0,0 +1,245 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
+
|
3
|
+
describe "Reittiopas()" do
|
4
|
+
before { @account = {:username => 'foo', :password => 'bar'} }
|
5
|
+
|
6
|
+
context "when called with an account hash as argument" do
|
7
|
+
subject { Reittiopas(@account) }
|
8
|
+
|
9
|
+
it "should return a Reittiopas object" do
|
10
|
+
should be_a_kind_of(Reittiopas)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe Reittiopas do
|
16
|
+
before { @account = {:username => 'foo', :password => 'bar'} }
|
17
|
+
|
18
|
+
context "when initialized with an account" do
|
19
|
+
subject { Reittiopas.new(@account) }
|
20
|
+
|
21
|
+
it { should respond_to(:location) }
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "#location" do
|
25
|
+
before { @reittiopas = Reittiopas.new(@account) }
|
26
|
+
|
27
|
+
context "when given key 'tee' that returns 18 locations from API" do
|
28
|
+
before do
|
29
|
+
response = File.read(File.dirname(__FILE__) + '/fixtures/key.xml')
|
30
|
+
stub_request(:any, /.*key=tee.*/).to_return(:body => response, :status => 200)
|
31
|
+
end
|
32
|
+
|
33
|
+
subject { @reittiopas.location('tee') }
|
34
|
+
|
35
|
+
it "should return 18 locations in an array" do
|
36
|
+
should have(18).items
|
37
|
+
|
38
|
+
subject.each do |obj|
|
39
|
+
obj.should be_a Reittiopas::Location
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context "when given KKJ coordinates that return one location from API" do
|
45
|
+
before do
|
46
|
+
response = File.read(File.dirname(__FILE__) + '/fixtures/reverse_geocoding.xml')
|
47
|
+
stub_request(:any, /(?:x|y)=\d+&(?:x|y)=\d+/).to_return(:body => response, :status => 200)
|
48
|
+
end
|
49
|
+
|
50
|
+
subject { @reittiopas.location(:x => 2546445, :y => 6675512) }
|
51
|
+
|
52
|
+
it "should return one result" do
|
53
|
+
should have(1).item
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should return a location" do
|
57
|
+
subject.first.should be_a Reittiopas::Location
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should return a location with KKJ coordinates" do
|
61
|
+
subject.last.coordinates[:kkj].x.should eql 2546445
|
62
|
+
subject.last.coordinates[:kkj].y.should eql 6675512
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe Reittiopas::HTTP do
|
69
|
+
it "should have the proper base API URI" do
|
70
|
+
Reittiopas::HTTP::API_BASE_URI.should eql(BASE_URI)
|
71
|
+
end
|
72
|
+
|
73
|
+
before do
|
74
|
+
@account = {:username => 'foo', :password => 'bar'}
|
75
|
+
@http = Reittiopas::HTTP.new(@account)
|
76
|
+
end
|
77
|
+
|
78
|
+
context "when initialized with an account" do
|
79
|
+
subject { Reittiopas::HTTP.new(@account) }
|
80
|
+
it { should respond_to(:get) }
|
81
|
+
|
82
|
+
it "should create an API URI with account details" do
|
83
|
+
subject.api_uri.query_values.
|
84
|
+
should eql('user' => @account[:username], 'pass' => @account[:password])
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe "#get" do
|
89
|
+
context "with empty hash as argument" do
|
90
|
+
it { lambda { @http.get({}) }.should raise_error(ArgumentError) }
|
91
|
+
end
|
92
|
+
|
93
|
+
context "with proper hash as argument" do
|
94
|
+
before do
|
95
|
+
@opts = {'key' => 'Keihäänheittäjänkuja 12'}
|
96
|
+
@uri = @http.api_uri
|
97
|
+
@uri.query_values = @uri.query_values.merge(@opts)
|
98
|
+
end
|
99
|
+
|
100
|
+
it "should create a request" do
|
101
|
+
stub_request(:get, Regexp.new(BASE_URI))
|
102
|
+
@http.get(@opts)
|
103
|
+
request(:get, @uri.to_s).should have_been_made
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should return response body on successful request" do
|
107
|
+
stub_request(:get, @uri.to_s).to_return(:body => 'hello', :status => 200)
|
108
|
+
@http.get(@opts).should eql('hello')
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
describe Reittiopas::Location do
|
115
|
+
it { should respond_to :name }
|
116
|
+
it { should respond_to :city }
|
117
|
+
it { should respond_to :type }
|
118
|
+
|
119
|
+
describe "#parse" do
|
120
|
+
context "when given LOC" do
|
121
|
+
context "example 1" do
|
122
|
+
xml = parse_elem '<LOC name1="Sello" number="" city="Espoo" code="2112201" address="Ratsukuja" type="10" category="stop" x="2545011" y="6678850" lon="24.80882" lat="60.21867"/>'
|
123
|
+
subject { Reittiopas::Location.parse xml }
|
124
|
+
|
125
|
+
it { subject.should be_a Reittiopas::Location::Stop }
|
126
|
+
it { subject.address.should eql 'Ratsukuja' }
|
127
|
+
it { subject.city.should eql 'Espoo' }
|
128
|
+
it { subject.name.should eql 'Sello' }
|
129
|
+
it { subject.type.should eql 10 }
|
130
|
+
it { subject.code.should eql 2112201 }
|
131
|
+
it { subject.coordinates[:kkj].x.should eql 2545011 }
|
132
|
+
it { subject.coordinates[:kkj].y.should eql 6678850 }
|
133
|
+
it { subject.coordinates[:wgs].longitude.should eql 24.80882 }
|
134
|
+
it { subject.coordinates[:wgs].latitude.should eql 60.21867 }
|
135
|
+
it { subject.to_s.should eql 'Sello' }
|
136
|
+
end
|
137
|
+
|
138
|
+
context "example 2" do
|
139
|
+
xml = parse_elem '<LOC name1="Kahisevantie" number="2" city="Espoo" code="" address="" type="900" category="street" x="2541494" y="6680344" lon="24.74568" lat="60.23245"/>'
|
140
|
+
subject { Reittiopas::Location.parse xml }
|
141
|
+
|
142
|
+
it { subject.should be_a Reittiopas::Location::Street }
|
143
|
+
it { subject.should_not respond_to :address }
|
144
|
+
it { subject.should_not respond_to :code }
|
145
|
+
it { subject.city.should eql 'Espoo' }
|
146
|
+
it { subject.name.should eql 'Kahisevantie' }
|
147
|
+
it { subject.type.should eql 900 }
|
148
|
+
it { subject.number.should eql 2 }
|
149
|
+
it { subject.coordinates[:kkj].x.should eql 2541494 }
|
150
|
+
it { subject.coordinates[:kkj].y.should eql 6680344 }
|
151
|
+
it { subject.coordinates[:wgs].longitude.should eql 24.74568 }
|
152
|
+
it { subject.coordinates[:wgs].latitude.should eql 60.23245 }
|
153
|
+
it { subject.to_s.should eql 'Kahisevantie 2' }
|
154
|
+
end
|
155
|
+
|
156
|
+
context "example 3" do
|
157
|
+
xml = parse_elem '<LOC name1="Teeripuisto" number="" city="Helsinki" code="1700" address="" type="3" category="poi" x="2556686" y="6682815" lon="25.02051" lat="60.2528" />'
|
158
|
+
subject { Reittiopas::Location.parse xml }
|
159
|
+
|
160
|
+
it { subject.should be_a Reittiopas::Location::PointOfInterest }
|
161
|
+
it { subject.should_not respond_to :address }
|
162
|
+
it { subject.city.should eql 'Helsinki' }
|
163
|
+
it { subject.name.should eql 'Teeripuisto' }
|
164
|
+
it { subject.type.should eql 3 }
|
165
|
+
it { subject.coordinates[:kkj].x.should eql 2556686 }
|
166
|
+
it { subject.coordinates[:kkj].y.should eql 6682815 }
|
167
|
+
it { subject.coordinates[:wgs].longitude.should eql 25.02051 }
|
168
|
+
it { subject.coordinates[:wgs].latitude.should eql 60.2528 }
|
169
|
+
it { subject.to_s.should eql 'Teeripuisto' }
|
170
|
+
end
|
171
|
+
|
172
|
+
context "example 4" do
|
173
|
+
xml = parse_elem '<LOC name1="Otakaari" number="9" city="Espoo" />'
|
174
|
+
subject { Reittiopas::Location.parse xml }
|
175
|
+
|
176
|
+
it { subject.should be_a Reittiopas::Location }
|
177
|
+
it { subject.city.should eql 'Espoo' }
|
178
|
+
it { subject.name.should eql 'Otakaari' }
|
179
|
+
it { subject.number.should eql 9 }
|
180
|
+
it { subject.should_not respond_to :address }
|
181
|
+
it { subject.should_not respond_to :code }
|
182
|
+
it { subject.type.should_not be }
|
183
|
+
it { subject.coordinates.should_not be }
|
184
|
+
it { subject.to_s.should eql 'Otakaari 9' }
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
context "when given LOC has 'poi' as category" do
|
189
|
+
xml = parse_elem '<LOC name1="Teeripuisto" number="" city="Helsinki" code="1700" address="" type="3" category="poi" x="2556686" y="6682815" lon="25.02051" lat="60.2528" />'
|
190
|
+
subject { Reittiopas::Location.parse xml }
|
191
|
+
|
192
|
+
it "should return a Location" do
|
193
|
+
should be_a Reittiopas::Location::PointOfInterest
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
context "when given LOC has 'stop' as category" do
|
198
|
+
xml = parse_elem '<LOC name1="Teeritie" number="" city="Vantaa" code="4810204" address="Korsontie" type="10" category="stop" x="2559002" y="6694007" lon="25.06559" lat="60.35291" />'
|
199
|
+
subject { Reittiopas::Location.parse xml }
|
200
|
+
|
201
|
+
it "should return a Stop" do
|
202
|
+
should be_a Reittiopas::Location::Stop
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
context "when given LOC has 'street' as category" do
|
207
|
+
xml = parse_elem '<LOC name1="Kahisevantie" number="2" city="Espoo" code="" address="" type="900" category="street" x="2541494" y="6680344" lon="24.74568" lat="60.23245"/>'
|
208
|
+
subject { Reittiopas::Location.parse xml }
|
209
|
+
|
210
|
+
it "should return a Street" do
|
211
|
+
should be_a Reittiopas::Location::Street
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
describe Reittiopas::Location::PointOfInterest do
|
218
|
+
it { should respond_to :code }
|
219
|
+
end
|
220
|
+
|
221
|
+
describe Reittiopas::Location::Stop do
|
222
|
+
it { should respond_to :address }
|
223
|
+
it { should respond_to :code }
|
224
|
+
end
|
225
|
+
|
226
|
+
describe Reittiopas::Location::Street do
|
227
|
+
it { should respond_to :number }
|
228
|
+
it { should_not respond_to :code }
|
229
|
+
end
|
230
|
+
|
231
|
+
describe Reittiopas::Location::Coordinates::KKJ do
|
232
|
+
subject { Reittiopas::Location::Coordinates::KKJ.new(:x => 2541494, :y => 6680344) }
|
233
|
+
|
234
|
+
it { should respond_to :x }
|
235
|
+
it { should respond_to :y }
|
236
|
+
end
|
237
|
+
|
238
|
+
describe Reittiopas::Location::Coordinates::WGS do
|
239
|
+
subject { Reittiopas::Location::Coordinates::WGS.new(:lon => 24.74568, :lat => 60.23245) }
|
240
|
+
|
241
|
+
it { should respond_to :latitude }
|
242
|
+
it { should respond_to :longitude }
|
243
|
+
|
244
|
+
it { subject.to_s.should eql '60.23245, 24.74568' }
|
245
|
+
end
|
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
begin
|
2
|
+
require 'spec'
|
3
|
+
rescue LoadError
|
4
|
+
require 'rubygems' unless ENV['NO_RUBYGEMS']
|
5
|
+
gem 'rspec'
|
6
|
+
require 'spec'
|
7
|
+
end
|
8
|
+
|
9
|
+
$:.unshift(File.dirname(__FILE__) + '/../lib')
|
10
|
+
require 'reittiopas'
|
11
|
+
|
12
|
+
require 'webmock/rspec'
|
13
|
+
include WebMock
|
14
|
+
|
15
|
+
BASE_URI = "http://api.reittiopas.fi/public-ytv/fi/api/"
|
16
|
+
|
17
|
+
def parse_elem(xml)
|
18
|
+
Nokogiri::XML(xml).children[0]
|
19
|
+
end
|
data/tasks/rspec.rake
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
begin
|
2
|
+
require 'spec'
|
3
|
+
rescue LoadError
|
4
|
+
require 'rubygems' unless ENV['NO_RUBYGEMS']
|
5
|
+
require 'spec'
|
6
|
+
end
|
7
|
+
begin
|
8
|
+
require 'spec/rake/spectask'
|
9
|
+
rescue LoadError
|
10
|
+
puts <<-EOS
|
11
|
+
To use rspec for testing you must install rspec gem:
|
12
|
+
gem install rspec
|
13
|
+
EOS
|
14
|
+
exit(0)
|
15
|
+
end
|
16
|
+
|
17
|
+
desc "Run the specs under spec/models"
|
18
|
+
Spec::Rake::SpecTask.new do |t|
|
19
|
+
t.spec_opts = ['--options', "spec/spec.opts"]
|
20
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
21
|
+
end
|
22
|
+
|
23
|
+
namespace :spec do
|
24
|
+
desc "Run all examples with RCov"
|
25
|
+
Spec::Rake::SpecTask.new(:rcov) do |t|
|
26
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
27
|
+
t.rcov = true
|
28
|
+
t.rcov_opts = [
|
29
|
+
'--exclude', 'spec'
|
30
|
+
]
|
31
|
+
end
|
32
|
+
|
33
|
+
desc "Browse the code coverage report."
|
34
|
+
task :browse => "spec:rcov" do
|
35
|
+
require "launchy"
|
36
|
+
Launchy::Browser.run("coverage/index.html")
|
37
|
+
end
|
38
|
+
end
|
metadata
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: reittiopas
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
version: 0.0.1
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Raine Virta
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-04-05 00:00:00 +03:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: webmock
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 0
|
29
|
+
version: "0"
|
30
|
+
type: :development
|
31
|
+
version_requirements: *id001
|
32
|
+
- !ruby/object:Gem::Dependency
|
33
|
+
name: hoe
|
34
|
+
prerelease: false
|
35
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
segments:
|
40
|
+
- 2
|
41
|
+
- 6
|
42
|
+
- 0
|
43
|
+
version: 2.6.0
|
44
|
+
type: :development
|
45
|
+
version_requirements: *id002
|
46
|
+
description: |-
|
47
|
+
Reittiopas is a Ruby library for accessing the {Reittiopas Developer API}[http://developer.reittiopas.fi/pages/fi/reittiopas-api.php].
|
48
|
+
|
49
|
+
Requires an account to the service that can be requested through {the account request page}[http://developer.reittiopas.fi/pages/fi/accountrequest.php].
|
50
|
+
email:
|
51
|
+
- raine.virta@gmail.com
|
52
|
+
executables: []
|
53
|
+
|
54
|
+
extensions: []
|
55
|
+
|
56
|
+
extra_rdoc_files:
|
57
|
+
- History.txt
|
58
|
+
- Manifest.txt
|
59
|
+
- README.rdoc
|
60
|
+
files:
|
61
|
+
- History.txt
|
62
|
+
- Manifest.txt
|
63
|
+
- README.rdoc
|
64
|
+
- Rakefile
|
65
|
+
- deps.rip
|
66
|
+
- lib/reittiopas.rb
|
67
|
+
- lib/reittiopas/coordinates.rb
|
68
|
+
- lib/reittiopas/geocoding.rb
|
69
|
+
- lib/reittiopas/http.rb
|
70
|
+
- lib/reittiopas/location.rb
|
71
|
+
- lib/reittiopas/reittiopas.rb
|
72
|
+
- lib/reittiopas/utils.rb
|
73
|
+
- script/console
|
74
|
+
- script/destroy
|
75
|
+
- script/generate
|
76
|
+
- spec/fixtures/key.xml
|
77
|
+
- spec/fixtures/reverse_geocoding.xml
|
78
|
+
- spec/reittiopas_spec.rb
|
79
|
+
- spec/spec.opts
|
80
|
+
- spec/spec_helper.rb
|
81
|
+
- tasks/rspec.rake
|
82
|
+
has_rdoc: true
|
83
|
+
homepage: http://github.com/raneksi/reittiopas
|
84
|
+
licenses: []
|
85
|
+
|
86
|
+
post_install_message:
|
87
|
+
rdoc_options:
|
88
|
+
- --main
|
89
|
+
- README.rdoc
|
90
|
+
require_paths:
|
91
|
+
- lib
|
92
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
segments:
|
97
|
+
- 0
|
98
|
+
version: "0"
|
99
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
segments:
|
104
|
+
- 0
|
105
|
+
version: "0"
|
106
|
+
requirements: []
|
107
|
+
|
108
|
+
rubyforge_project: reittiopas
|
109
|
+
rubygems_version: 1.3.6
|
110
|
+
signing_key:
|
111
|
+
specification_version: 3
|
112
|
+
summary: Reittiopas is a Ruby library for accessing the {Reittiopas Developer API}[http://developer.reittiopas.fi/pages/fi/reittiopas-api.php]
|
113
|
+
test_files: []
|
114
|
+
|