reittiopas2 0.0.3 → 0.0.4
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.
- checksums.yaml +4 -4
- data/Guardfile +0 -1
- data/README.md +9 -22
- data/Rakefile +2 -3
- data/lib/reittiopas2.rb +6 -6
- data/lib/reittiopas2/client.rb +58 -0
- data/lib/reittiopas2/geocoding.rb +95 -97
- data/lib/reittiopas2/routing.rb +122 -123
- data/lib/reittiopas2/utilities.rb +29 -0
- data/lib/reittiopas2/version.rb +1 -1
- data/reittiopas2.gemspec +1 -3
- data/spec/{connection_spec.rb → client_spec.rb} +9 -15
- data/spec/geocoding_spec.rb +1 -11
- data/spec/routing_spec.rb +1 -1
- data/spec/spec_helper.rb +8 -7
- metadata +7 -7
- data/lib/reittiopas2/connection.rb +0 -58
- data/lib/reittiopas2/util.rb +0 -30
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 31fc0c7d85affb2fb20f9997bb0c269e55d322db
|
4
|
+
data.tar.gz: e320d9f0e2cad1f809c5cfd31a73ae8bcda48308
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7bfa10688c67662e66c25af1cd8f3efdaede9a277ec62861ff4eab32ad83ca1cd844407554389d0b460ce56c9ba11c20a9edca120ebad59997126d3d0bee162e
|
7
|
+
data.tar.gz: e8f247cdd0a7f6dc867a057f3ca3dcfd4c081f694034f0f2d8f7b8c5e4effd6c91b1679fb09bf90c416b4adc049ac54bedc9d4fba13a394e13f98ba6cbcbdfff
|
data/Guardfile
CHANGED
data/README.md
CHANGED
@@ -1,32 +1,19 @@
|
|
1
|
-
#
|
1
|
+
# Reittiopas 2
|
2
2
|
|
3
|
-
|
4
|
-
[reittiopas v2 API](http://developer.reittiopas.fi/pages/fi/reittiopas-api.php),
|
5
|
-
providing simple route searching and geocoding.
|
3
|
+
Reittiopas 2 is a simple Ruby library for accessing the [Reittiopas API][API].
|
6
4
|
|
5
|
+
[API]: http://developer.reittiopas.fi/pages/en/http-get-interface-version-2.php
|
7
6
|
|
8
|
-
## Installation
|
9
|
-
|
10
|
-
Add this line to your application's Gemfile:
|
11
|
-
|
12
|
-
gem 'reittiopas2'
|
13
7
|
|
14
|
-
|
15
|
-
|
16
|
-
$ bundle
|
8
|
+
## Installation
|
17
9
|
|
18
|
-
|
10
|
+
Install using [Bundler][]:
|
19
11
|
|
20
|
-
|
12
|
+
gem 'reittiopas2', '~> 0.0.3'
|
21
13
|
|
22
|
-
|
14
|
+
[Bundler]: http://bundler.io/
|
23
15
|
|
24
|
-
Sadly, you have to dive into docstrings for documentation.
|
25
16
|
|
26
|
-
##
|
17
|
+
## License
|
27
18
|
|
28
|
-
|
29
|
-
2. Create your feature branch (`git checkout -b my-new-feature`)
|
30
|
-
3. Commit your changes (`git commit -am 'Added some feature'`)
|
31
|
-
4. Push to the branch (`git push origin my-new-feature`)
|
32
|
-
5. Create new Pull Request
|
19
|
+
Reittiopas 2 is released under the MIT License. See `LICENSE` for details.
|
data/Rakefile
CHANGED
data/lib/reittiopas2.rb
CHANGED
@@ -1,15 +1,15 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
1
|
+
require 'reittiopas2/client'
|
2
|
+
require 'reittiopas2/geocoding'
|
3
|
+
require 'reittiopas2/routing'
|
4
|
+
require 'reittiopas2/utilities'
|
5
|
+
require 'reittiopas2/version'
|
6
6
|
|
7
7
|
class Reittiopas2
|
8
8
|
include Geocoding
|
9
9
|
include Routing
|
10
10
|
|
11
11
|
def initialize(username, password)
|
12
|
-
@
|
12
|
+
@client = Reittiopas2::Client.new(username, password)
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'reittiopas2/utilities'
|
2
|
+
|
3
|
+
require 'addressable/uri'
|
4
|
+
require 'json'
|
5
|
+
require 'net/http'
|
6
|
+
|
7
|
+
class Reittiopas2
|
8
|
+
|
9
|
+
# Handles connectting to Reittiopas API and transforms query hashes into form
|
10
|
+
# that Reittiopas API can digest them. This class is also responsible for
|
11
|
+
# parsing response into Ruby readable form.
|
12
|
+
#
|
13
|
+
# @api private
|
14
|
+
class Client
|
15
|
+
include Utilities
|
16
|
+
|
17
|
+
def initialize(username, password)
|
18
|
+
@base_url = "http://api.reittiopas.fi/hsl/prod/"
|
19
|
+
@base_query = {"user" => username, "pass" => password}
|
20
|
+
end
|
21
|
+
|
22
|
+
# Forms proper query from credentials + given query and sends it to API
|
23
|
+
# endpoint. Also parses response into Ruby readable form.
|
24
|
+
#
|
25
|
+
# In case of errors, be those from API endpoint or from internal processes,
|
26
|
+
# return value will be hash with one field 'error' which contains error
|
27
|
+
# message.
|
28
|
+
#
|
29
|
+
# In fatal error situations Exception will be thrown, only exception for this
|
30
|
+
# rule is JSON::ParserException which is caught and returned as value of
|
31
|
+
# 'error' field.
|
32
|
+
#
|
33
|
+
# @param [Hash] query the query which is to be sent to API endpoint
|
34
|
+
# @return [Hash] the whatever data was requested from API, or Hash containing
|
35
|
+
# key 'error' containing error message.
|
36
|
+
def perform_query(query={})
|
37
|
+
query = convert_array_values(query)
|
38
|
+
uri = Addressable::URI.parse(@base_url)
|
39
|
+
uri.query_values = @base_query.merge(query)
|
40
|
+
|
41
|
+
res = Net::HTTP.get_response(uri)
|
42
|
+
|
43
|
+
if res.code == '500'
|
44
|
+
# In case of errors, code 500 is returned and there is explanation in
|
45
|
+
# response body as HTML.
|
46
|
+
{'error' => res.body}
|
47
|
+
elsif res.body.nil? or res.body.empty?
|
48
|
+
{'error' => "Response body was empty!"}
|
49
|
+
else
|
50
|
+
JSON.load res.body.to_s
|
51
|
+
end
|
52
|
+
rescue JSON::ParserError => ex
|
53
|
+
{'error' => ex.class}
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
@@ -1,111 +1,109 @@
|
|
1
|
-
require
|
1
|
+
require 'reittiopas2/utilities'
|
2
2
|
|
3
3
|
class Reittiopas2
|
4
4
|
|
5
|
-
# Module containing public API to perform geocoding and reverse geocoding
|
6
|
-
# operations.
|
7
|
-
#
|
8
|
-
# Location info returned from geocode methods is following form:
|
9
|
-
# @example geocode location info
|
10
|
-
# [
|
11
|
-
# {
|
12
|
-
# 'locType' => 'stop',
|
13
|
-
# 'locTypeId' => '10',
|
14
|
-
# 'name' => 'Elielinaukio',
|
15
|
-
# 'matchedName' => 'Elielinaukio',
|
16
|
-
# 'lang' => 'fi',
|
17
|
-
# 'city' => 'Helsinki',
|
18
|
-
# 'coords' => '2552335,6673660',
|
19
|
-
# 'details' => {
|
20
|
-
# 'address' => 'Elielinaukio',
|
21
|
-
# 'code' => '1020128',
|
22
|
-
# 'shortCode' => '2020',
|
23
|
-
# 'lines' => [
|
24
|
-
# '1015A 1:Länsiterminaali',
|
25
|
-
# '1015A 2:Elielinaukio'
|
26
|
-
# ]
|
27
|
-
# }
|
28
|
-
# }
|
29
|
-
# ]
|
30
|
-
#
|
31
|
-
#
|
32
|
-
# @example reverse_geocode location info
|
33
|
-
# [
|
34
|
-
# {
|
35
|
-
# 'locType' => 'address',
|
36
|
-
# 'locTypeId' => '900',
|
37
|
-
# 'name' => 'Purotie 8, Helsinki',
|
38
|
-
# 'matchedName' => nil,
|
39
|
-
# 'lang' => 'fi',
|
40
|
-
# 'city' => 'Helsinki',
|
41
|
-
# 'coords' => '2552335,6673660',
|
42
|
-
# 'distance' => '38.4187454245971',
|
43
|
-
# 'details' => {
|
44
|
-
# 'address' => nil,
|
45
|
-
# 'houseNumber' => '8',
|
46
|
-
# }
|
47
|
-
# }
|
48
|
-
# ]
|
49
|
-
#
|
50
|
-
module Geocoding
|
51
|
-
|
52
|
-
# Search for information about place.
|
53
|
-
#
|
54
|
-
# @param [String] place_name the name of place to be searched. This can be
|
55
|
-
# street name, point of interest, bus stop, etc.
|
56
|
-
# @param [Hash] opts the optional parameters which can be used to alter search
|
57
|
-
# results. Any invalid keys are removed from query parameters, but values
|
58
|
-
# are never checked.
|
5
|
+
# Module containing public API to perform geocoding and reverse geocoding
|
6
|
+
# operations.
|
59
7
|
#
|
60
|
-
#
|
61
|
-
# @
|
62
|
-
#
|
63
|
-
#
|
64
|
-
#
|
65
|
-
#
|
66
|
-
#
|
67
|
-
#
|
68
|
-
#
|
8
|
+
# Location info returned from geocode methods is following form:
|
9
|
+
# @example geocode location info
|
10
|
+
# [
|
11
|
+
# {
|
12
|
+
# 'locType' => 'stop',
|
13
|
+
# 'locTypeId' => '10',
|
14
|
+
# 'name' => 'Elielinaukio',
|
15
|
+
# 'matchedName' => 'Elielinaukio',
|
16
|
+
# 'lang' => 'fi',
|
17
|
+
# 'city' => 'Helsinki',
|
18
|
+
# 'coords' => '2552335,6673660',
|
19
|
+
# 'details' => {
|
20
|
+
# 'address' => 'Elielinaukio',
|
21
|
+
# 'code' => '1020128',
|
22
|
+
# 'shortCode' => '2020',
|
23
|
+
# 'lines' => [
|
24
|
+
# '1015A 1:Länsiterminaali',
|
25
|
+
# '1015A 2:Elielinaukio'
|
26
|
+
# ]
|
27
|
+
# }
|
28
|
+
# }
|
29
|
+
# ]
|
69
30
|
#
|
70
|
-
# @return [Array<Hash>] array containing location hashes matched given query.
|
71
|
-
# @see #reverse_geocode
|
72
|
-
def geocode(place_name, opts={})
|
73
|
-
clean = Util.select_keys(opts, GEOCODE_KEYS)
|
74
|
-
query = {'request' =>'geocode', 'key' => place_name}.merge(clean)
|
75
|
-
@connection.perform_query(query)
|
76
|
-
end
|
77
|
-
|
78
|
-
|
79
|
-
# Do reverse geocode search to find information about given coordinates.
|
80
31
|
#
|
81
|
-
# @
|
82
|
-
#
|
83
|
-
#
|
84
|
-
#
|
32
|
+
# @example reverse_geocode location info
|
33
|
+
# [
|
34
|
+
# {
|
35
|
+
# 'locType' => 'address',
|
36
|
+
# 'locTypeId' => '900',
|
37
|
+
# 'name' => 'Purotie 8, Helsinki',
|
38
|
+
# 'matchedName' => nil,
|
39
|
+
# 'lang' => 'fi',
|
40
|
+
# 'city' => 'Helsinki',
|
41
|
+
# 'coords' => '2552335,6673660',
|
42
|
+
# 'distance' => '38.4187454245971',
|
43
|
+
# 'details' => {
|
44
|
+
# 'address' => nil,
|
45
|
+
# 'houseNumber' => '8',
|
46
|
+
# }
|
47
|
+
# }
|
48
|
+
# ]
|
85
49
|
#
|
86
|
-
|
87
|
-
|
88
|
-
# @option opts [Integer] 'radius' (1000) Radius of the search in meters. Range
|
89
|
-
# 1-1000.
|
90
|
-
# @option opts [String] 'result_contains' ('address') Limit the search to
|
91
|
-
# given location types. Possible values are: address, stop, poi
|
92
|
-
#
|
93
|
-
# @return [Array<Hash>] array containing location hashes matching given
|
94
|
-
# coordinates.
|
95
|
-
# @see #geocode
|
96
|
-
def reverse_geocode(coords, opts={})
|
97
|
-
clean = Util.select_keys(opts, REVERSE_GEOCODE_KEYS)
|
98
|
-
query = {'request' => 'reverse_geocode', 'coordinate' => coords}.merge(clean)
|
99
|
-
@connection.perform_query(query)
|
100
|
-
end
|
50
|
+
module Geocoding
|
51
|
+
include Utilities
|
101
52
|
|
53
|
+
# Search for information about place.
|
54
|
+
#
|
55
|
+
# @param [String] place_name the name of place to be searched. This can be
|
56
|
+
# street name, point of interest, bus stop, etc.
|
57
|
+
# @param [Hash] opts the optional parameters which can be used to alter search
|
58
|
+
# results. Any invalid keys are removed from query parameters, but values
|
59
|
+
# are never checked.
|
60
|
+
#
|
61
|
+
# @option opts [String] 'cities' ('all') List of cities which are accepted.
|
62
|
+
# @option opts [String] 'loc_types' ('all') List of location types which are
|
63
|
+
# accepted.
|
64
|
+
# @option opts [Integer] 'disable_error_correction' (0) Disable levenshtein
|
65
|
+
# error correction. 1 = Error correction NOT in use, 0 = error correction in
|
66
|
+
# use.
|
67
|
+
# @option opts [Integer] 'disable_unique_stop_names' (1) Disable unique stop
|
68
|
+
# names in the result. 1 = all stops are shown in the result, 0 = only one
|
69
|
+
# stop is included in the result for stops with same name.
|
70
|
+
#
|
71
|
+
# @return [Array<Hash>] array containing location hashes matched given query.
|
72
|
+
# @see #reverse_geocode
|
73
|
+
def geocode(place_name, opts={})
|
74
|
+
clean = select_keys(opts, GEOCODE_KEYS)
|
75
|
+
query = {'request' =>'geocode', 'key' => place_name}.merge(clean)
|
76
|
+
@client.perform_query(query)
|
77
|
+
end
|
102
78
|
|
103
|
-
|
104
|
-
|
79
|
+
# Do reverse geocode search to find information about given coordinates.
|
80
|
+
#
|
81
|
+
# @param [String] coords the coordinate pair "<x_coordinate>,<y_coordinate>"
|
82
|
+
# @param [Hash] opts the optional parameters which can be used to alter query
|
83
|
+
# results. Any invalid keys are removed from query parameters, but values
|
84
|
+
# are never checked.
|
85
|
+
#
|
86
|
+
# @option opts [Integer] 'limit' (1) Limit for the number of locations
|
87
|
+
# returned.
|
88
|
+
# @option opts [Integer] 'radius' (1000) Radius of the search in meters. Range
|
89
|
+
# 1-1000.
|
90
|
+
# @option opts [String] 'result_contains' ('address') Limit the search to
|
91
|
+
# given location types. Possible values are: address, stop, poi
|
92
|
+
#
|
93
|
+
# @return [Array<Hash>] array containing location hashes matching given
|
94
|
+
# coordinates.
|
95
|
+
# @see #geocode
|
96
|
+
def reverse_geocode(coords, opts={})
|
97
|
+
clean = select_keys(opts, REVERSE_GEOCODE_KEYS)
|
98
|
+
query = {'request' => 'reverse_geocode', 'coordinate' => coords}.merge(clean)
|
99
|
+
@client.perform_query(query)
|
100
|
+
end
|
105
101
|
|
106
|
-
|
102
|
+
GEOCODE_KEYS = ['key', 'cities', 'loc_types', 'disable_error_correction',
|
103
|
+
'disable_unique_stop_names']
|
107
104
|
|
108
|
-
|
105
|
+
REVERSE_GEOCODE_KEYS = ['coordinate', 'limit', 'radius', 'result_contains']
|
109
106
|
|
107
|
+
end
|
110
108
|
|
111
109
|
end
|
data/lib/reittiopas2/routing.rb
CHANGED
@@ -1,138 +1,137 @@
|
|
1
|
-
require 'reittiopas2/
|
1
|
+
require 'reittiopas2/utilities'
|
2
2
|
|
3
3
|
class Reittiopas2
|
4
4
|
|
5
|
-
# Routing module contains all needed functionality to query route information.
|
6
|
-
module Routing
|
5
|
+
# Routing module contains all needed functionality to query route information.
|
6
|
+
module Routing
|
7
|
+
include Utilities
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
9
|
+
# Query the route between two coordinate points. In routing it is recommended
|
10
|
+
# to use street addresses (their coordinates) as it is difficult for the end
|
11
|
+
# user to know where exactly a stop is located. There might be several stops
|
12
|
+
# with the same name that are located far away from each other (for example
|
13
|
+
# the stop 'Sturenkatu' in Helsinki).
|
14
|
+
#
|
15
|
+
# @param [String, Hash] from Coordinates where route begins.
|
16
|
+
# @param [String, Hash] to Coordinates where route ends.
|
17
|
+
# @param [Hash] opts Optional parameters to query.
|
18
|
+
# @return [Hash] the route between given points.
|
19
|
+
#
|
20
|
+
# @option opts [String] via
|
21
|
+
# @option opts [Number] date (Current date) YYYYMMDD
|
22
|
+
# @option opts [Number] time (Current time) HHMM
|
23
|
+
# @option opts [String] timetype ('departure') Time of the request is either
|
24
|
+
# * 'departure'
|
25
|
+
# * 'arrival'
|
26
|
+
# @option opts [Number] via_time Minimum time spent at a via_point in
|
27
|
+
# minutes.
|
28
|
+
# @option opts [String] zone (No restriction) Ticket zone, possible values
|
29
|
+
# are:
|
30
|
+
# * 'helsinki',
|
31
|
+
# * 'espoo',
|
32
|
+
# * 'vantaa',
|
33
|
+
# * 'whole' (Helsinki, Espoo, Kauniainen, Vantaa, Kirkkonummi and Kerava.
|
34
|
+
# Whole region, excluding non HSL areas),
|
35
|
+
# * 'region' (Helsinki, Espoo, Kauniainen and Vantaa region)
|
36
|
+
# @option opts [String, Array<String>] transport_types ('all') Transport
|
37
|
+
# types included in the request. Possible types are:
|
38
|
+
# * 'all',
|
39
|
+
# * 'bus',
|
40
|
+
# * 'train',
|
41
|
+
# * 'metro',
|
42
|
+
# * 'tram',
|
43
|
+
# * 'service',
|
44
|
+
# * 'U-line',
|
45
|
+
# * 'ferry',
|
46
|
+
# * 'walk' (ONLY walking)
|
47
|
+
# @option opts [String] optimize ('default') Routing profile. Possible
|
48
|
+
# values:
|
49
|
+
# * 'default' = (wait cost=1.0, walk cost=1.2, change cost=6),
|
50
|
+
# * 'fastest' = (wait cost=1.0, walk cost=1.0, change cost=0),
|
51
|
+
# * 'least_transfers' = (wait cost=1.0, walk cost=1.5, change cost=20),
|
52
|
+
# * 'least_walking' = (wait cost=1.0, walk cost=5.0, change cost=6)
|
53
|
+
# @option opts [Number] change_margin (3) The minimum number of minutes
|
54
|
+
# between changes. Range 0-10.
|
55
|
+
# @option opts [Number] change_cost Penalty for a change, user is rather
|
56
|
+
# N minutes later at the destination than changes to another vehicle. Range
|
57
|
+
# 1-99. This parameter overrides the setting from optimize.
|
58
|
+
# @option opts [Number] wait_cost With this parameter you can weigh wait
|
59
|
+
# time cost when calculating fastest route. Range 0.1 – 10.0. This
|
60
|
+
# parameter overrides optimize parameter.
|
61
|
+
# @option opts [Number] walk_speed (70) Walking speed. m/min, range 1-500.
|
62
|
+
# @option opts [String] detail ('normal') Detail level of the response.
|
63
|
+
# Possible values:
|
64
|
+
# * 'limited' = only legs are returned,
|
65
|
+
# * 'normal' = intermiediate stops are returned,
|
66
|
+
# * 'full' = route share coordinates are returned
|
67
|
+
# @option opts [Number] show (3) Number of routes in the response.
|
68
|
+
# @option opts [Number] mode_cost_|transport_type_id| Mode costs for different
|
69
|
+
# transport types. These settings override previous values set with
|
70
|
+
# transport_types-parameter. Values may range from 0.1 to 10 or it can be -1
|
71
|
+
# when the transport type is excluded from routing.
|
72
|
+
#
|
73
|
+
# transport_type_id in the parameter name may be any of the following:
|
74
|
+
# 1. Helsinki internal bus lines
|
75
|
+
# 2. trams
|
76
|
+
# 3. Espoo internal bus lines
|
77
|
+
# 4. Vantaa internal bus lines
|
78
|
+
# 5. regional bus lines
|
79
|
+
# 6. metro
|
80
|
+
# 7. ferry
|
81
|
+
# 8. U-lines
|
82
|
+
# 12. commuter trains
|
83
|
+
# 21. Helsinki service lines
|
84
|
+
# 22. Helsinki night buses
|
85
|
+
# 23. Espoo service lines
|
86
|
+
# 24. Vantaa service lines
|
87
|
+
# 25. region night buses
|
88
|
+
# 36. Kirkkonummi internal bus lines
|
89
|
+
# 39. Kerava internal bus lines
|
90
|
+
def route(from, to, opts={})
|
91
|
+
if from.class != to.class
|
92
|
+
return {'error' => 'ArgumentError: from.class != to.class'}
|
93
|
+
end
|
94
|
+
|
95
|
+
if from.is_a? String
|
96
|
+
query = route_query_from_strings(from, to)
|
97
|
+
elsif from.is_a? Hash and from['coordinate'] and to['coordinate']
|
98
|
+
query = route_query_from_locations(from, to)
|
99
|
+
else
|
100
|
+
return {'error' => 'ArgumentError: locations were not acceptable types'}
|
101
|
+
end
|
93
102
|
|
94
|
-
|
95
|
-
query
|
96
|
-
elsif from.is_a? Hash and from['coordinate'] and to['coordinate']
|
97
|
-
query = route_query_from_locations(from, to)
|
98
|
-
else
|
99
|
-
return {'error' => 'ArgumentError: locations were not acceptable types'}
|
103
|
+
clean_opts = select_keys(opts, KEYS + MODE_COSTS)
|
104
|
+
@client.perform_query(clean_opts.merge(query))
|
100
105
|
end
|
101
106
|
|
102
|
-
|
103
|
-
@connection.perform_query(clean_opts.merge(query))
|
104
|
-
end
|
107
|
+
private
|
105
108
|
|
109
|
+
def route_query_from_strings(from, to)
|
110
|
+
{
|
111
|
+
'request' => 'route',
|
112
|
+
'from' => from,
|
113
|
+
'to' => to
|
114
|
+
}
|
115
|
+
end
|
106
116
|
|
107
|
-
|
117
|
+
def route_query_from_locations(from, to)
|
118
|
+
{
|
119
|
+
'request' => 'route',
|
120
|
+
'from' => from['coordinate'],
|
121
|
+
'to' => to['coordinate']
|
122
|
+
}
|
123
|
+
end
|
108
124
|
|
125
|
+
KEYS = ['via', 'date', 'time', 'timetype', 'via_time', 'zone',
|
126
|
+
'transport_types', 'optimize', 'change_margin', 'change_cost',
|
127
|
+
'wait_cost', 'walk_cost', 'walk_speed', 'detail', 'show']
|
109
128
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
}
|
116
|
-
end
|
129
|
+
MODE_COSTS = ['mode_cost_1', 'mode_cost_2', 'mode_cost_3', 'mode_cost_4',
|
130
|
+
'mode_cost_5', 'mode_cost_6', 'mode_cost_7', 'mode_cost_7',
|
131
|
+
'mode_cost_8', 'mode_cost_12', 'mode_cost_21', 'mode_cost_22',
|
132
|
+
'mode_cost_23', 'mode_cost_24', 'mode_cost_25', 'mode_cost_36',
|
133
|
+
'mode_cost_39']
|
117
134
|
|
118
|
-
def route_query_from_locations(from, to)
|
119
|
-
{
|
120
|
-
'request' => 'route',
|
121
|
-
'from' => from['coordinate'],
|
122
|
-
'to' => to['coordinate']
|
123
|
-
}
|
124
135
|
end
|
125
136
|
|
126
|
-
KEYS = ['via', 'date', 'time', 'timetype', 'via_time', 'zone',
|
127
|
-
'transport_types', 'optimize', 'change_margin', 'change_cost',
|
128
|
-
'wait_cost', 'walk_cost', 'walk_speed', 'detail', 'show']
|
129
|
-
|
130
|
-
MODE_COSTS = ['mode_cost_1', 'mode_cost_2', 'mode_cost_3', 'mode_cost_4',
|
131
|
-
'mode_cost_5', 'mode_cost_6', 'mode_cost_7', 'mode_cost_7',
|
132
|
-
'mode_cost_8', 'mode_cost_12', 'mode_cost_21', 'mode_cost_22',
|
133
|
-
'mode_cost_23', 'mode_cost_24', 'mode_cost_25', 'mode_cost_36',
|
134
|
-
'mode_cost_39']
|
135
|
-
|
136
|
-
end
|
137
|
-
|
138
137
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class Reittiopas2
|
2
|
+
module Utilities
|
3
|
+
module_function
|
4
|
+
|
5
|
+
# Converts array values into string values containing array members joined
|
6
|
+
# by pipe ('|') characters.
|
7
|
+
#
|
8
|
+
# @param [Hash] a hash
|
9
|
+
# @return [Hash] a hash
|
10
|
+
def convert_array_values(hash)
|
11
|
+
result = hash.map do |key, value|
|
12
|
+
if value.is_a? Array
|
13
|
+
[key, value.join('|')]
|
14
|
+
else
|
15
|
+
[key, value]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
Hash[result]
|
20
|
+
end
|
21
|
+
|
22
|
+
def select_keys(hash, keys)
|
23
|
+
hash.select do |key, value|
|
24
|
+
keys.include? key
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
data/lib/reittiopas2/version.rb
CHANGED
data/reittiopas2.gemspec
CHANGED
@@ -10,10 +10,8 @@ Gem::Specification.new do |gem|
|
|
10
10
|
gem.license = "MIT"
|
11
11
|
|
12
12
|
gem.files = `git ls-files`.split($\)
|
13
|
-
gem.
|
14
|
-
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
13
|
+
gem.test_files = gem.files.grep(%r{^spec/})
|
15
14
|
gem.name = "reittiopas2"
|
16
|
-
gem.require_paths = ["lib"]
|
17
15
|
gem.version = Reittiopas2::VERSION
|
18
16
|
|
19
17
|
gem.add_dependency "json", "~> 1.8"
|
@@ -1,17 +1,15 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
|
-
describe Reittiopas2::
|
3
|
+
describe Reittiopas2::Client do
|
4
4
|
before :each do
|
5
5
|
@user = "username"
|
6
6
|
@pwd = "password"
|
7
|
-
@
|
7
|
+
@client = Reittiopas2::Client.new @user, @pwd
|
8
8
|
|
9
9
|
@base_url = "http://api.reittiopas.fi/hsl/prod/"
|
10
10
|
@query = {"user" => @user, "pass" => @pwd}
|
11
11
|
end
|
12
12
|
|
13
|
-
|
14
|
-
|
15
13
|
describe "query forming" do
|
16
14
|
it "should put pipes into arrays" do
|
17
15
|
q = @query.merge({ "array" => ["one", "two", "three"] })
|
@@ -20,21 +18,19 @@ describe Reittiopas2::Connection do
|
|
20
18
|
stub_request(:get, @base_url).
|
21
19
|
with(:query => expected_q)
|
22
20
|
|
23
|
-
@
|
21
|
+
@client.perform_query(q)
|
24
22
|
a_request(:get, @base_url).with(:query => expected_q).should have_been_made
|
25
23
|
end
|
26
24
|
|
27
|
-
|
28
25
|
it "should form query only with credentials in case no query given." do
|
29
26
|
stub_request(:get, @base_url).
|
30
27
|
with(:query => @query)
|
31
28
|
|
32
|
-
@
|
29
|
+
@client.perform_query
|
33
30
|
a_request(:get, @base_url).with(:query => @query).should have_been_made
|
34
31
|
end
|
35
32
|
end
|
36
33
|
|
37
|
-
|
38
34
|
describe "perform_query return value" do
|
39
35
|
it "should be hash filled with data in case of succesful query." do
|
40
36
|
body = '{"max":5000,"used":44}'
|
@@ -44,11 +40,10 @@ describe Reittiopas2::Connection do
|
|
44
40
|
with(:query => query).
|
45
41
|
to_return(:body => body)
|
46
42
|
|
47
|
-
ret = @
|
43
|
+
ret = @client.perform_query(query)
|
48
44
|
ret.should == {"max" => 5000, "used" => 44}
|
49
45
|
end
|
50
46
|
|
51
|
-
|
52
47
|
it "should have response body in error field in case of 500 code" do
|
53
48
|
body = "Hello! Error!"
|
54
49
|
|
@@ -56,11 +51,10 @@ describe Reittiopas2::Connection do
|
|
56
51
|
with(:query => @query).
|
57
52
|
to_return(:status => 500, :body => body)
|
58
53
|
|
59
|
-
ret = @
|
54
|
+
ret = @client.perform_query
|
60
55
|
ret.should == {'error' => body}
|
61
56
|
end
|
62
57
|
|
63
|
-
|
64
58
|
it "should error field in case of JSON parse error" do
|
65
59
|
body = "well this is not valid JSON"
|
66
60
|
|
@@ -68,7 +62,7 @@ describe Reittiopas2::Connection do
|
|
68
62
|
with(:query => @query).
|
69
63
|
to_return(:body => body)
|
70
64
|
|
71
|
-
ret = @
|
65
|
+
ret = @client.perform_query
|
72
66
|
ret['error'].should_not be_nil
|
73
67
|
end
|
74
68
|
|
@@ -77,7 +71,7 @@ describe Reittiopas2::Connection do
|
|
77
71
|
with(:query => @query).
|
78
72
|
to_return(:body => '')
|
79
73
|
|
80
|
-
ret = @
|
74
|
+
ret = @client.perform_query
|
81
75
|
ret.should == {'error' => 'Response body was empty!'}
|
82
76
|
end
|
83
77
|
end
|
data/spec/geocoding_spec.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Reittiopas2::Geocoding do
|
4
4
|
|
@@ -11,14 +11,12 @@ describe Reittiopas2::Geocoding do
|
|
11
11
|
@base_url = "http://api.reittiopas.fi/hsl/prod/"
|
12
12
|
end
|
13
13
|
|
14
|
-
|
15
14
|
describe "geocoding" do
|
16
15
|
before :each do
|
17
16
|
@city = 'Helsinki'
|
18
17
|
@query = @base_query.merge('request' => 'geocode', 'key' => @city)
|
19
18
|
end
|
20
19
|
|
21
|
-
|
22
20
|
it "should perform request to API geocode endpoint." do
|
23
21
|
stub_request(:get, @base_url).
|
24
22
|
with(:query => @query)
|
@@ -29,7 +27,6 @@ describe Reittiopas2::Geocoding do
|
|
29
27
|
with(:query => @query).should have_been_made.once
|
30
28
|
end
|
31
29
|
|
32
|
-
|
33
30
|
it "should send only valid keys to API" do
|
34
31
|
valid_opts = {
|
35
32
|
'cities' => ["helsinki", "espoo"],
|
@@ -45,7 +42,6 @@ describe Reittiopas2::Geocoding do
|
|
45
42
|
"disable_unique_stop_names" => 0
|
46
43
|
}
|
47
44
|
|
48
|
-
|
49
45
|
query = @query.merge(opts_query_form)
|
50
46
|
opts = valid_opts.merge('not_valid_key' => 'or value')
|
51
47
|
|
@@ -58,7 +54,6 @@ describe Reittiopas2::Geocoding do
|
|
58
54
|
with(:query => query).should have_been_made.once
|
59
55
|
end
|
60
56
|
|
61
|
-
|
62
57
|
it "should return hash of location hashes if query is success" do
|
63
58
|
opts = {'loc_types' => 'stop'}
|
64
59
|
|
@@ -72,7 +67,6 @@ describe Reittiopas2::Geocoding do
|
|
72
67
|
locs[0].should be_kind_of(Hash)
|
73
68
|
end
|
74
69
|
end
|
75
|
-
|
76
70
|
|
77
71
|
describe "reverse geocoding" do
|
78
72
|
before :each do
|
@@ -81,7 +75,6 @@ describe Reittiopas2::Geocoding do
|
|
81
75
|
'coordinate' => @coords)
|
82
76
|
end
|
83
77
|
|
84
|
-
|
85
78
|
it "should perform request to API reverse_geocode endpoint." do
|
86
79
|
stub_request(:get, @base_url).
|
87
80
|
with(:query => @query)
|
@@ -92,7 +85,6 @@ describe Reittiopas2::Geocoding do
|
|
92
85
|
with(:query => @query).should have_been_made.once
|
93
86
|
end
|
94
87
|
|
95
|
-
|
96
88
|
it "should send only valid keys to API" do
|
97
89
|
valid_opts = {
|
98
90
|
'coordinate' => '2552335,6673660',
|
@@ -108,7 +100,6 @@ describe Reittiopas2::Geocoding do
|
|
108
100
|
"result_contains" => "stop"
|
109
101
|
}
|
110
102
|
|
111
|
-
|
112
103
|
opts = valid_opts.merge('not_valid_key' => 'or value')
|
113
104
|
query = @query.merge(opts_query_form)
|
114
105
|
|
@@ -121,7 +112,6 @@ describe Reittiopas2::Geocoding do
|
|
121
112
|
with(:query => query).should have_been_made.once
|
122
113
|
end
|
123
114
|
|
124
|
-
|
125
115
|
it "should return hash of location hashes if query is success" do
|
126
116
|
json = File.new('spec/data/reverse_geocode.json')
|
127
117
|
stub_request(:get, @base_url).
|
data/spec/routing_spec.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
require 'webmock/rspec'
|
4
4
|
|
5
|
-
require
|
6
|
-
SimpleCov.start
|
7
|
-
|
8
|
-
|
5
|
+
require 'simplecov'
|
6
|
+
SimpleCov.start do
|
7
|
+
add_filter "/vendor/"
|
8
|
+
end
|
9
9
|
|
10
|
+
require 'reittiopas2'
|
10
11
|
|
11
12
|
RSpec.configure do |config|
|
12
13
|
config.treat_symbols_as_metadata_keys_with_true_values = true
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: reittiopas2
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Iivari Äikäs
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2014-01-20 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: json
|
@@ -124,13 +124,13 @@ files:
|
|
124
124
|
- README.md
|
125
125
|
- Rakefile
|
126
126
|
- lib/reittiopas2.rb
|
127
|
-
- lib/reittiopas2/
|
127
|
+
- lib/reittiopas2/client.rb
|
128
128
|
- lib/reittiopas2/geocoding.rb
|
129
129
|
- lib/reittiopas2/routing.rb
|
130
|
-
- lib/reittiopas2/
|
130
|
+
- lib/reittiopas2/utilities.rb
|
131
131
|
- lib/reittiopas2/version.rb
|
132
132
|
- reittiopas2.gemspec
|
133
|
-
- spec/
|
133
|
+
- spec/client_spec.rb
|
134
134
|
- spec/data/geocode.json
|
135
135
|
- spec/data/reverse_geocode.json
|
136
136
|
- spec/geocoding_spec.rb
|
@@ -156,12 +156,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
156
156
|
version: '0'
|
157
157
|
requirements: []
|
158
158
|
rubyforge_project:
|
159
|
-
rubygems_version: 2.0.
|
159
|
+
rubygems_version: 2.0.3
|
160
160
|
signing_key:
|
161
161
|
specification_version: 4
|
162
162
|
summary: Gem providing easy access to reittiopas version 2 API.
|
163
163
|
test_files:
|
164
|
-
- spec/
|
164
|
+
- spec/client_spec.rb
|
165
165
|
- spec/data/geocode.json
|
166
166
|
- spec/data/reverse_geocode.json
|
167
167
|
- spec/geocoding_spec.rb
|
@@ -1,58 +0,0 @@
|
|
1
|
-
require 'reittiopas2/util'
|
2
|
-
|
3
|
-
require 'addressable/uri'
|
4
|
-
require 'json'
|
5
|
-
require 'net/http'
|
6
|
-
|
7
|
-
class Reittiopas2
|
8
|
-
|
9
|
-
# Handles connectting to Reittiopas API and transforms query hashes into form
|
10
|
-
# that Reittiopas API can digest them. This class is also responsible for
|
11
|
-
# parsing response into Ruby readable form.
|
12
|
-
#
|
13
|
-
# @api private
|
14
|
-
class Connection
|
15
|
-
|
16
|
-
def initialize(username, password)
|
17
|
-
@base_url = "http://api.reittiopas.fi/hsl/prod/"
|
18
|
-
@base_query = {"user" => username, "pass" => password}
|
19
|
-
end
|
20
|
-
|
21
|
-
|
22
|
-
# Forms proper query from credentials + given query and sends it to API
|
23
|
-
# endpoint. Also parses response into Ruby readable form.
|
24
|
-
#
|
25
|
-
# In case of errors, be those from API endpoint or from internal processes,
|
26
|
-
# return value will be hash with one field 'error' which contains error
|
27
|
-
# message.
|
28
|
-
#
|
29
|
-
# In fatal error situations Exception will be thrown, only exception for this
|
30
|
-
# rule is JSON::ParserException which is caught and returned as value of
|
31
|
-
# 'error' field.
|
32
|
-
#
|
33
|
-
# @param [Hash] query the query which is to be sent to API endpoint
|
34
|
-
# @return [Hash] the whatever data was requested from API, or Hash containing
|
35
|
-
# key 'error' containing error message.
|
36
|
-
def perform_query(query={})
|
37
|
-
query = Util.convert_array_values(query)
|
38
|
-
uri = Addressable::URI.parse(@base_url)
|
39
|
-
uri.query_values = @base_query.merge(query)
|
40
|
-
|
41
|
-
res = Net::HTTP.get_response(uri)
|
42
|
-
|
43
|
-
if res.code == '500'
|
44
|
-
# In case of errors, code 500 is returned and there is explanation in
|
45
|
-
# response body as HTML.
|
46
|
-
{'error' => res.body}
|
47
|
-
elsif res.body.nil? or res.body.empty?
|
48
|
-
{'error' => "Response body was empty!"}
|
49
|
-
else
|
50
|
-
JSON.load res.body.to_s
|
51
|
-
end
|
52
|
-
rescue JSON::ParserError => ex
|
53
|
-
{'error' => ex.class}
|
54
|
-
end
|
55
|
-
|
56
|
-
end
|
57
|
-
|
58
|
-
end
|
data/lib/reittiopas2/util.rb
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
class Reittiopas2
|
2
|
-
|
3
|
-
module Util
|
4
|
-
|
5
|
-
# Converts array values into string values containing array members joined
|
6
|
-
# by pipe ('|') characters.
|
7
|
-
#
|
8
|
-
# @param [Hash] a hash
|
9
|
-
# @return [Hash] a hash
|
10
|
-
def self.convert_array_values(hash)
|
11
|
-
result = hash.map do |key, value|
|
12
|
-
if value.is_a? Array
|
13
|
-
[key, value.join('|')]
|
14
|
-
else
|
15
|
-
[key, value]
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
Hash[result]
|
20
|
-
end
|
21
|
-
|
22
|
-
def self.select_keys(hash, keys)
|
23
|
-
hash.select do |key, value|
|
24
|
-
keys.include? key
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
end
|
29
|
-
|
30
|
-
end
|