gdsapi-v2-ruby 0.1.3 → 0.1.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/gdsapi-v2-ruby.gemspec +1 -1
- data/lib/gdsapi/client.rb +69 -71
- data/lib/gdsapi/methods/base_method.rb +83 -85
- data/lib/gdsapi/methods/get_available_trips.rb +22 -24
- data/lib/gdsapi/methods/get_countries.rb +28 -30
- data/lib/gdsapi/methods/get_locations.rb +50 -52
- data/lib/gdsapi/methods/get_points.rb +48 -50
- data/lib/gdsapi/methods/utils/parse_utils.rb +22 -24
- data/lib/gdsapi/methods.rb +1 -3
- data/lib/gdsapi/requester.rb +37 -39
- data/lib/gdsapi/structs/country.rb +10 -12
- data/lib/gdsapi/structs/location.rb +14 -16
- data/lib/gdsapi/structs/point.rb +9 -11
- data/lib/gdsapi/structs.rb +7 -9
- data/lib/gdsapi/version.rb +1 -3
- data/lib/gdsapi.rb +14 -16
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 682cc9ed559e0b6ac5d9af4074e5341b4b5d7c3a
|
|
4
|
+
data.tar.gz: 62b93de7d2a463f4a77d818068570ae0a066301c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 430c0da15dab2bb293d415e9b30f740048ebe3e1a118c33d3c34b15805104ea54371ea8c00df23c4212421a2380da81257aa85ff6d17c82ed2c6a8c14f2c372e
|
|
7
|
+
data.tar.gz: 681427cad7b61007cf738f8017dc01498714da4f4afb89d76cd6ab8635dbad071e9cc87efd7b4700f5b04b96c34ba09876979c7ed09c2643ba76f300d9d058dd
|
data/gdsapi-v2-ruby.gemspec
CHANGED
data/lib/gdsapi/client.rb
CHANGED
|
@@ -1,85 +1,83 @@
|
|
|
1
1
|
# Facade class for performing GDS requests
|
|
2
2
|
module Gdsapi
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
attr_reader :requester
|
|
3
|
+
class Client
|
|
4
|
+
attr_reader :requester
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class << self
|
|
14
|
-
# Constructing routine that uses Faraday as driver
|
|
15
|
-
# @param base_url: url param for Faraday(requred)
|
|
16
|
-
# @param login: & password: - HTTP basic auth factors
|
|
17
|
-
# @param language: - language slug for which request will be performed (available are: en, ru, uk, pl, th)
|
|
18
|
-
def with_faraday_requester(base_url: nil, login: nil, password: nil, language: nil)
|
|
19
|
-
driver = Faraday.new(url: base_url)
|
|
20
|
-
new(Requester.new(driver, login: login, password: password, language: language))
|
|
21
|
-
end
|
|
6
|
+
# @param [Gdsapi::Requester] requester - requester instance
|
|
7
|
+
# It is `strongly recommended` to use Faraday(see ##with_faraday_requester)
|
|
8
|
+
def initialize(requester)
|
|
9
|
+
@requester = requester
|
|
10
|
+
end
|
|
22
11
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
12
|
+
class << self
|
|
13
|
+
# Constructing routine that uses Faraday as driver
|
|
14
|
+
# @param base_url: url param for Faraday(requred)
|
|
15
|
+
# @param login: & password: - HTTP basic auth factors
|
|
16
|
+
# @param language: - language slug for which request will be performed (available are: en, ru, uk, pl, th)
|
|
17
|
+
def with_faraday_requester(base_url: nil, login: nil, password: nil, language: nil)
|
|
18
|
+
driver = Faraday.new(url: base_url)
|
|
19
|
+
new(Requester.new(driver, login: login, password: password, language: language))
|
|
30
20
|
end
|
|
31
21
|
|
|
32
|
-
#
|
|
33
|
-
|
|
34
|
-
|
|
22
|
+
# Constructing routine that uses given driver
|
|
23
|
+
# @param driver - driver instance
|
|
24
|
+
# @param login: & password: - HTTP basic auth factors
|
|
25
|
+
# @param language: - language slug for which request will be performed (available are: en, ru, uk, pl, th)
|
|
26
|
+
def with_requester(driver, login: nil, password: nil, language: nil)
|
|
27
|
+
new(Requester.new(driver, login: login, password: password, language: language))
|
|
35
28
|
end
|
|
29
|
+
end
|
|
36
30
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
# :offset [Number|String] - number of records to be skipped when fetching chunks (optional)
|
|
42
|
-
# :limit [Number|String] - number of records to be fetched when fetching chunks (optional)
|
|
43
|
-
# :timestamp [String] - temporal checkpoint(i.e. date, records from which are interested)
|
|
44
|
-
# (optional, format: yyyy-MM-dd’T’HH:mm:ssZ, GMT+2)
|
|
45
|
-
def get_locations(**args)
|
|
46
|
-
Methods::GetLocations.new(requester).call(**args)
|
|
47
|
-
end
|
|
31
|
+
# Ad-hoc solution for adding multilanguage support
|
|
32
|
+
def language=(value)
|
|
33
|
+
requester.language = value
|
|
34
|
+
end
|
|
48
35
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
end
|
|
36
|
+
# GDS Method used to fetch GDS locations
|
|
37
|
+
# For more information, see [http://demo.gillbus.com/v2/doc.html#получение-географии-получение-списка-остановок-get]
|
|
38
|
+
# @param args - keyword args:
|
|
39
|
+
# :country [Number|String] - GDS country id for which locations are fetched (optional)
|
|
40
|
+
# :offset [Number|String] - number of records to be skipped when fetching chunks (optional)
|
|
41
|
+
# :limit [Number|String] - number of records to be fetched when fetching chunks (optional)
|
|
42
|
+
# :timestamp [String] - temporal checkpoint(i.e. date, records from which are interested)
|
|
43
|
+
# (optional, format: yyyy-MM-dd’T’HH:mm:ssZ, GMT+2)
|
|
44
|
+
def get_locations(**args)
|
|
45
|
+
Methods::GetLocations.new(requester).call(**args)
|
|
46
|
+
end
|
|
61
47
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
48
|
+
# GDS Method used to fetch GDS points
|
|
49
|
+
# For more information, see [http://demo.gillbus.com/v2/doc.html#получение-географии-получение-списка-остановок-get]
|
|
50
|
+
# @param args - keyword args:
|
|
51
|
+
# :country [Number|String] - GDS country id for which points are fetched (optional)
|
|
52
|
+
# :location [Number|String] - GDS location id for which points are fetched (optional)
|
|
53
|
+
# :offset [Number|String] - number of records to be skipped when fetching chunks (optional)
|
|
54
|
+
# :limit [Number|String] - number of records to be fetched when fetching chunks (optional)
|
|
55
|
+
# :timestamp [String] - temporal checkpoint(i.e. date, records from which are interested)
|
|
56
|
+
# (optional, format: yyyy-MM-dd’T’HH:mm:ssZ, GMT+2)
|
|
57
|
+
def get_points(**args)
|
|
58
|
+
Methods::GetPoints.new(requester).call(**args)
|
|
59
|
+
end
|
|
70
60
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
61
|
+
# GDS Method used to fetch GDS countries
|
|
62
|
+
# For more information, see [http://demo.gillbus.com/v2/doc.html#получение-географии-страны-get]
|
|
63
|
+
# @param args - keyword args:
|
|
64
|
+
# :offset [Number|String] - number of records to be skipped when fetching chunks (optional)
|
|
65
|
+
# :limit [Number|String] - number of records to be fetched when fetching chunks (optional)
|
|
66
|
+
def get_countries(**args)
|
|
67
|
+
Methods::GetCountries.new(requester).call(**args)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# GDS Method used to check availability of trips
|
|
71
|
+
# For more information, see [http://demo.gillbus.com/v2/doc.html#поиск-рейсов-доступность-рейсов-get]
|
|
72
|
+
# @param args - keyword args:
|
|
73
|
+
# :arrival [String] - GDS arrival point id (required)
|
|
74
|
+
# :departure [String] - GDS departure point id (required)
|
|
75
|
+
# :tickets [Number] - number of tickets for trip (required)
|
|
76
|
+
# :mode [Number] - transport type (optional, buses are: 1,8)
|
|
77
|
+
# :dates [String] - dates for trip (required, format: yyyy-mm-dd, delimiter: ';')
|
|
78
|
+
# :return_only_branded [Boolean] - returns data only for branded trips if true
|
|
79
|
+
def get_available_trips(**args)
|
|
80
|
+
Methods::GetAvailableTrips.new(requester).call(**args)
|
|
83
81
|
end
|
|
84
82
|
end
|
|
85
83
|
end
|
|
@@ -1,103 +1,101 @@
|
|
|
1
1
|
require_relative 'utils/parse_utils'
|
|
2
2
|
|
|
3
3
|
module Gdsapi
|
|
4
|
-
module
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
attr_reader :requester
|
|
4
|
+
module Methods
|
|
5
|
+
class BaseMethod
|
|
6
|
+
include ParseUtils
|
|
7
|
+
attr_reader :requester
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
9
|
+
# Constructor method for passing requester instance
|
|
10
|
+
# @param [[Gdsapi::Requester]] - requester instance
|
|
11
|
+
def initialize(requester)
|
|
12
|
+
@requester = requester
|
|
13
|
+
end
|
|
15
14
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
15
|
+
## Generic entry-point for action
|
|
16
|
+
## @param hash_styled `list` and `offset` args used for chunking requests
|
|
17
|
+
## @return - parsed results
|
|
18
|
+
def call(**params)
|
|
19
|
+
response_body = query params
|
|
20
|
+
body = JSON.parse response_body
|
|
21
|
+
parse body
|
|
22
|
+
rescue JSON::ParserError
|
|
23
|
+
raise MalformedGdsResponse, "Invalid JSON: #{response_body}"
|
|
24
|
+
end
|
|
26
25
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
26
|
+
protected
|
|
27
|
+
# HTTP verb used to query GDS API for method
|
|
28
|
+
# Defaults to :get
|
|
29
|
+
# @return [Symbol] - symbolic alias for requester method corresponding to HTTP verb (i.e., :get or :post)
|
|
30
|
+
def method
|
|
31
|
+
:get
|
|
32
|
+
end
|
|
34
33
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
34
|
+
# GDS API path for method
|
|
35
|
+
# It is required for method to specify path
|
|
36
|
+
def parse(*args)
|
|
37
|
+
raise NotImplementedError, 'Parsing is not allowed for abstract method'
|
|
38
|
+
end
|
|
40
39
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
40
|
+
# GDS API path for method
|
|
41
|
+
# It is required for method to specify path
|
|
42
|
+
def path
|
|
43
|
+
raise NotImplementedError, 'Querying is not allowed for abstract method'
|
|
44
|
+
end
|
|
46
45
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
end
|
|
46
|
+
# Query routine to be executed while performing action
|
|
47
|
+
# @param [Hash] args - args used for querying
|
|
48
|
+
# @return [String] - response body string
|
|
49
|
+
def query(args)
|
|
50
|
+
params = transform_params(slice_params(args))
|
|
51
|
+
response = requester.public_send(method, path, params: params)
|
|
52
|
+
case response.status
|
|
53
|
+
when (404)
|
|
54
|
+
raise NotFoundError, "Not found on #{response.env.url}"
|
|
55
|
+
when (401)
|
|
56
|
+
raise UnathorizedError, "Invalid auth on #{response.env.url}"
|
|
57
|
+
when (400..499)
|
|
58
|
+
raise BadRequestError, "Bad request on #{response.env.url}: #{response.body.to_s}"
|
|
59
|
+
when (500..599)
|
|
60
|
+
raise GdsInternalError, "#{response.status} #{response.body.to_s}"
|
|
61
|
+
when (300..399)
|
|
62
|
+
raise GdsRedirectError, "#{response.status} #{response.headers['Location'].to_s}"
|
|
63
|
+
else
|
|
64
|
+
response.body
|
|
67
65
|
end
|
|
66
|
+
end
|
|
68
67
|
|
|
69
68
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
69
|
+
# Transform params with accordance to requirements of API
|
|
70
|
+
# @param [Hash[Symbol => Object]] filtered_params - passed params
|
|
71
|
+
# @return [Hash[Symbol => Object]] transformed set of params
|
|
72
|
+
def transform_params(filtered_params)
|
|
73
|
+
filtered_params
|
|
74
|
+
end
|
|
76
75
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
76
|
+
# Select params which are allowed in querying for the method
|
|
77
|
+
# @param [Hash[Symbol => Object]] params - passed params
|
|
78
|
+
# @return [Hash[Symbol => Object]] params filtered using whitelist (see #permitted_params) and by presence (!nil?)
|
|
79
|
+
def slice_params(params)
|
|
80
|
+
params.select { |name, value| permitted_params.include?(name) && value }
|
|
81
|
+
end
|
|
83
82
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
83
|
+
# whitelist of permitted params
|
|
84
|
+
# defaults to empty list
|
|
85
|
+
# @return [Array[Symbol]] - params that are permitted for given instance of method
|
|
86
|
+
def permitted_params
|
|
87
|
+
[]
|
|
88
|
+
end
|
|
90
89
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
end
|
|
90
|
+
# Editing geodata modes mapping (GDS -> output)
|
|
91
|
+
# Used when dealing with temporal data (i.e. given timestamps)
|
|
92
|
+
# U (upsert) - update or create record
|
|
93
|
+
# D (delete) - delete record
|
|
94
|
+
def modes
|
|
95
|
+
{
|
|
96
|
+
'U' => :upsert,
|
|
97
|
+
'D' => :delete,
|
|
98
|
+
}
|
|
101
99
|
end
|
|
102
100
|
end
|
|
103
101
|
end
|
|
@@ -1,33 +1,31 @@
|
|
|
1
1
|
# GDS Method class used to check availability of trips
|
|
2
2
|
# For more information, see [http://demo.gillbus.com/v2/doc.html#поиск-рейсов-доступность-рейсов-get]
|
|
3
3
|
module Gdsapi
|
|
4
|
-
module
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
private
|
|
4
|
+
module Methods
|
|
5
|
+
class GetAvailableTrips < BaseMethod
|
|
6
|
+
private
|
|
8
7
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
8
|
+
## Parsing routine to be executed while performing action
|
|
9
|
+
## Actually, does nothing
|
|
10
|
+
## @param [Array] body - parsed JSON payload from GDS
|
|
11
|
+
## @return [Array] set of available dates for given trip
|
|
12
|
+
def parse(body)
|
|
13
|
+
body
|
|
14
|
+
end
|
|
16
15
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
def path
|
|
17
|
+
'available_trips'
|
|
18
|
+
end
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
end
|
|
20
|
+
# Query params
|
|
21
|
+
# :arrival [String] - GDS arrival point id (required)
|
|
22
|
+
# :departure [String] - GDS departure point id (required)
|
|
23
|
+
# :tickets [Number] - number of tickets for trip (required)
|
|
24
|
+
# :mode [Number] - transport type (optional, buses are: 1,8)
|
|
25
|
+
# :dates [String] - dates for trip (required, format: yyyy-mm-dd, delimiter: ';')
|
|
26
|
+
# :return_only_branded [Boolean] - returns data only for branded trips if true
|
|
27
|
+
def permitted_params
|
|
28
|
+
%i(arrival departure tickets mode dates return_only_branded)
|
|
31
29
|
end
|
|
32
30
|
end
|
|
33
31
|
end
|
|
@@ -1,42 +1,40 @@
|
|
|
1
1
|
# GDS Method class used to fetch GDS countries
|
|
2
2
|
# For more information, see [http://demo.gillbus.com/v2/doc.html#получение-географии-страны-get]
|
|
3
3
|
module Gdsapi
|
|
4
|
-
module
|
|
5
|
-
|
|
6
|
-
class GetCountries < BaseMethod
|
|
4
|
+
module Methods
|
|
5
|
+
class GetCountries < BaseMethod
|
|
7
6
|
|
|
8
|
-
|
|
7
|
+
private
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
def path
|
|
10
|
+
'countries'
|
|
11
|
+
end
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
## Parsing routine to be executed while performing action
|
|
14
|
+
## @param [Hash] body - parsed JSON payload from GDS
|
|
15
|
+
## @return [Array[Gdsapi::Structs::Country]] parsed set of countries
|
|
16
|
+
def parse(body)
|
|
17
|
+
return [] if body.empty?
|
|
19
18
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
end
|
|
19
|
+
countries = body['countries']
|
|
20
|
+
types = body['types']
|
|
21
|
+
attributes = body['attributes']
|
|
22
|
+
countries.map do |country|
|
|
23
|
+
args = {
|
|
24
|
+
id: country['id'],
|
|
25
|
+
name: country['name'],
|
|
26
|
+
type: types.find { |type| type['id'] == country['type_id'] },
|
|
27
|
+
attributes: match_attributes(country['attributes'], attributes),
|
|
28
|
+
}
|
|
29
|
+
Gdsapi::Structs::Country.new args
|
|
32
30
|
end
|
|
31
|
+
end
|
|
33
32
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
end
|
|
33
|
+
# Query params
|
|
34
|
+
# :offset [Number|String] - number of records to be skipped when fetching chunks (optional)
|
|
35
|
+
# :limit [Number|String] - number of records to be fetched when fetching chunks (optional)
|
|
36
|
+
def permitted_params
|
|
37
|
+
%i(limit offset])
|
|
40
38
|
end
|
|
41
39
|
end
|
|
42
40
|
end
|
|
@@ -1,69 +1,67 @@
|
|
|
1
1
|
# GDS Method class used to fetch GDS locations
|
|
2
2
|
# For more information, see [http://demo.gillbus.com/v2/doc.html#получение-географии-получение-населенных-пунктов-get]
|
|
3
3
|
module Gdsapi
|
|
4
|
-
module
|
|
5
|
-
|
|
6
|
-
class GetLocations < BaseMethod
|
|
4
|
+
module Methods
|
|
5
|
+
class GetLocations < BaseMethod
|
|
7
6
|
|
|
8
|
-
|
|
7
|
+
private
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
9
|
+
# Parsing routine invoked on JSON response parsed to hash
|
|
10
|
+
# @param [Hash] body - given response hash from GDS
|
|
11
|
+
# @return [Hash[Symbol => Array[Gdsapi::Structs::Location]]] - location objects grouped by editing mode:
|
|
12
|
+
# :upsert - objects inserted or updated since given timestamp
|
|
13
|
+
# :delete - objects deleted since given timestamp
|
|
14
|
+
def parse(body)
|
|
15
|
+
return {} if body.empty?
|
|
17
16
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
end
|
|
37
|
-
[modes[mod], parsed_locations]
|
|
17
|
+
locations = body['locations']
|
|
18
|
+
types = body['types']
|
|
19
|
+
attributes = body['attributes']
|
|
20
|
+
sub_types = body['subTypes']
|
|
21
|
+
grouped_locations = locations.group_by { |location| location['mod'] }
|
|
22
|
+
parsed_locations = grouped_locations.map do |mod, hash_locations|
|
|
23
|
+
parsed_locations = hash_locations.map do |location|
|
|
24
|
+
args = {
|
|
25
|
+
id: location['id'],
|
|
26
|
+
name: location['name'],
|
|
27
|
+
latitude: location['latitude'],
|
|
28
|
+
longitude: location['longitude'],
|
|
29
|
+
parent: location['parent'],
|
|
30
|
+
type: types.find { |type| type['id'] == location['type_id'] },
|
|
31
|
+
sub_type: sub_types.find { |sub_type| sub_type['id'] == location['sub_type_id'] },
|
|
32
|
+
attributes: match_attributes(location['attributes'], attributes),
|
|
33
|
+
}
|
|
34
|
+
Gdsapi::Structs::Location.new args
|
|
38
35
|
end
|
|
39
|
-
|
|
36
|
+
[modes[mod], parsed_locations]
|
|
40
37
|
end
|
|
38
|
+
Hash[parsed_locations]
|
|
39
|
+
end
|
|
41
40
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
def path
|
|
42
|
+
'locations'
|
|
43
|
+
end
|
|
45
44
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
end
|
|
45
|
+
def transform_params(filtered_params)
|
|
46
|
+
filtered_params.tap do |params|
|
|
47
|
+
if params[:timestamp]
|
|
48
|
+
if params[:timestamp].respond_to?(:strftime)
|
|
49
|
+
params[:timestamp] = params[:timestamp].strftime('%FT%T%z')
|
|
50
|
+
else
|
|
51
|
+
params[:timestamp] = params[:timestamp].to_s
|
|
54
52
|
end
|
|
55
53
|
end
|
|
56
54
|
end
|
|
55
|
+
end
|
|
57
56
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
end
|
|
57
|
+
# Query params
|
|
58
|
+
# :country [Number|String] - GDS country id for which locations are fetched (optional)
|
|
59
|
+
# :offset [Number|String] - number of records to be skipped when fetching chunks (optional)
|
|
60
|
+
# :limit [Number|String] - number of records to be fetched when fetching chunks (optional)
|
|
61
|
+
# :timestamp [String] - temporal checkpoint(i.e. date, records from which are interested)
|
|
62
|
+
# (optional, format: yyyy-MM-dd’T’HH:mm:ssZ, GMT +2)
|
|
63
|
+
def permitted_params
|
|
64
|
+
%i(country offset limit timestamp)
|
|
67
65
|
end
|
|
68
66
|
end
|
|
69
67
|
end
|
|
@@ -1,67 +1,65 @@
|
|
|
1
1
|
# GDS Method class used to fetch GDS locations
|
|
2
2
|
# For more information, see [http://demo.gillbus.com/v2/doc.html#получение-географии-получение-списка-остановок-get]
|
|
3
3
|
module Gdsapi
|
|
4
|
-
module
|
|
5
|
-
|
|
6
|
-
class GetPoints < BaseMethod
|
|
4
|
+
module Methods
|
|
5
|
+
class GetPoints < BaseMethod
|
|
7
6
|
|
|
8
|
-
|
|
7
|
+
private
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
9
|
+
# Parsing routine invoked on JSON response parsed to hash
|
|
10
|
+
# @param [Hash] body - given response hash from GDS
|
|
11
|
+
# @return [Hash[Symbol => Array[Gdsapi::Structs::Point]]] - point objects grouped by editing mode:
|
|
12
|
+
# :upsert - objects inserted or updated since given timestamp
|
|
13
|
+
# :delete - objects deleted since given timestamp
|
|
14
|
+
def parse(body)
|
|
15
|
+
return {} if body.empty?
|
|
17
16
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
end
|
|
34
|
-
[modes[mod], parsed_points]
|
|
17
|
+
points = body['points']
|
|
18
|
+
attributes = body['attributes']
|
|
19
|
+
grouped_points = points.group_by { |point| point['mod'] }
|
|
20
|
+
parsed_points = grouped_points.map do |mod, hash_points|
|
|
21
|
+
parsed_points = hash_points.map do |point|
|
|
22
|
+
args = {
|
|
23
|
+
id: point['id'],
|
|
24
|
+
name: point['name'],
|
|
25
|
+
latitude: point['latitude'],
|
|
26
|
+
longitude: point['longitude'],
|
|
27
|
+
parent: point['parent'],
|
|
28
|
+
address: point['address'],
|
|
29
|
+
attributes: match_attributes(point['attributes'], attributes),
|
|
30
|
+
}
|
|
31
|
+
Gdsapi::Structs::Point.new args
|
|
35
32
|
end
|
|
36
|
-
|
|
33
|
+
[modes[mod], parsed_points]
|
|
37
34
|
end
|
|
35
|
+
Hash[parsed_points]
|
|
36
|
+
end
|
|
38
37
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
38
|
+
def path
|
|
39
|
+
'points'
|
|
40
|
+
end
|
|
42
41
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
end
|
|
42
|
+
def transform_params(filtered_params)
|
|
43
|
+
filtered_params.tap do |params|
|
|
44
|
+
if params[:timestamp]
|
|
45
|
+
if params[:timestamp].respond_to?(:strftime)
|
|
46
|
+
params[:timestamp] = params[:timestamp].strftime('%FT%T%z')
|
|
47
|
+
else
|
|
48
|
+
params[:timestamp] = params[:timestamp].to_s
|
|
51
49
|
end
|
|
52
50
|
end
|
|
53
51
|
end
|
|
52
|
+
end
|
|
54
53
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
end
|
|
54
|
+
# Query params
|
|
55
|
+
# :country [Number|String] - GDS country id for which points are fetched (optional)
|
|
56
|
+
# :location [Number|String] - GDS location id for which points are fetched (optional)
|
|
57
|
+
# :offset [Number|String] - number of records to be skipped when fetching chunks (optional)
|
|
58
|
+
# :limit [Number|String] - number of records to be fetched when fetching chunks (optional)
|
|
59
|
+
# :timestamp [String] - temporal checkpoint(i.e. date, records from which are interested)
|
|
60
|
+
# (optional, format: yyyy-MM-dd’T’HH:mm:ssZ, GMT +2)
|
|
61
|
+
def permitted_params
|
|
62
|
+
%i(country location offset limit timestamp)
|
|
65
63
|
end
|
|
66
64
|
end
|
|
67
65
|
end
|
|
@@ -1,32 +1,30 @@
|
|
|
1
1
|
# Module representing parsing utility methods
|
|
2
2
|
module Gdsapi
|
|
3
|
-
module
|
|
4
|
-
module
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
return unless set
|
|
3
|
+
module Methods
|
|
4
|
+
module ParseUtils
|
|
5
|
+
## Helping routine for matching given attributes with dictionary
|
|
6
|
+
## @param set [Array[Hash] | nil] - set of {'id', 'value'}-ish attributes for country
|
|
7
|
+
## @param dictionary [Array[Hash]] - dictionary of {'id', 'name'}-ish attributes
|
|
8
|
+
## @return [Array[Hash]|nil] - {id:, name:, value:}-ish attributes hash if set is present, nil otherwise
|
|
9
|
+
def match_attributes(set, dictionary)
|
|
10
|
+
return unless set
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
end
|
|
12
|
+
grouped_set = set.group_by { |attribute| attribute['id'] }
|
|
13
|
+
grouped_set.map do |id, set_attributes|
|
|
14
|
+
dictionary_attribute = dictionary.find {|dict_attr| dict_attr['id'] == id }
|
|
15
|
+
values = set_attributes.map { |set_attribute| set_attribute['value'] }
|
|
16
|
+
if dictionary_attribute
|
|
17
|
+
{
|
|
18
|
+
id: dictionary_attribute['id'],
|
|
19
|
+
name: dictionary_attribute['name'],
|
|
20
|
+
values: values,
|
|
21
|
+
}
|
|
22
|
+
else
|
|
23
|
+
raise MalformedGdsResponse,
|
|
24
|
+
"Invalid response: missing attribute #{id}"
|
|
27
25
|
end
|
|
28
26
|
end
|
|
29
27
|
end
|
|
30
28
|
end
|
|
31
29
|
end
|
|
32
|
-
end
|
|
30
|
+
end
|
data/lib/gdsapi/methods.rb
CHANGED
data/lib/gdsapi/requester.rb
CHANGED
|
@@ -2,52 +2,50 @@
|
|
|
2
2
|
# Encapsulates supportive data to be used when querying
|
|
3
3
|
# Also responsible for performing HTTP requests
|
|
4
4
|
module Gdsapi
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
attr_reader :language
|
|
5
|
+
class Requester
|
|
6
|
+
attr_reader :login
|
|
7
|
+
attr_reader :password
|
|
8
|
+
attr_reader :driver
|
|
9
|
+
attr_reader :language
|
|
11
10
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
11
|
+
# @param [Faraday::Connection] driver - driver instance, i.e. object that responds to
|
|
12
|
+
# #get(url, params, headers),
|
|
13
|
+
# #post(url, body, params),
|
|
14
|
+
# #basic_auth(login, password),
|
|
15
|
+
# and querying and modifying #headers in Hash-style
|
|
16
|
+
# It is `strongly recommended` to use Faraday
|
|
17
|
+
# @param login: & password: - HTTP basic auth factors
|
|
18
|
+
# @param language: - language slug for which request will be performed
|
|
19
|
+
def initialize(driver, login: '', password: '', language: 'ru')
|
|
20
|
+
@driver = driver
|
|
21
|
+
@login = login || ''
|
|
22
|
+
@password = password || ''
|
|
23
|
+
@language = language || 'ru'
|
|
24
|
+
set_language
|
|
25
|
+
set_basic_auth
|
|
26
|
+
end
|
|
28
27
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
def language=(value)
|
|
29
|
+
@language = value
|
|
30
|
+
set_language
|
|
31
|
+
end
|
|
33
32
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
def get(url, params: {}, headers: {})
|
|
34
|
+
driver.get url, params, headers
|
|
35
|
+
end
|
|
37
36
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
37
|
+
def post(url, body: {}, headers: {})
|
|
38
|
+
driver.post url, body, headers
|
|
39
|
+
end
|
|
41
40
|
|
|
42
|
-
|
|
41
|
+
private
|
|
43
42
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
def set_language
|
|
44
|
+
driver.headers['Accept-Language'] = language
|
|
45
|
+
end
|
|
47
46
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
end
|
|
47
|
+
def set_basic_auth
|
|
48
|
+
driver.basic_auth login, password
|
|
51
49
|
end
|
|
52
50
|
end
|
|
53
51
|
end
|
|
@@ -2,21 +2,19 @@ require_relative '../structs'
|
|
|
2
2
|
|
|
3
3
|
## Country struct
|
|
4
4
|
## Used when syncing geodata with GDS
|
|
5
|
-
## See [Gdsapi::
|
|
5
|
+
## See [Gdsapi::Methods::GetCountries] for details
|
|
6
6
|
## Also see http://demo.gillbus.com/v2/doc.html#получение-географии-страны for schema definition
|
|
7
7
|
module Gdsapi
|
|
8
|
-
module
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
attribute :attributes, Attributes.optional
|
|
8
|
+
module Structs
|
|
9
|
+
class Country < ::Dry::Struct
|
|
10
|
+
attribute :id, Structs::Coercible::Int
|
|
11
|
+
attribute :name, Structs::Coercible::String
|
|
12
|
+
attribute :type, Type.optional
|
|
13
|
+
attribute :attributes, Attributes.optional
|
|
15
14
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
end
|
|
15
|
+
def attribute_by_id(id)
|
|
16
|
+
if attributes && id
|
|
17
|
+
attributes.find {|attribute| attribute.id == id}
|
|
20
18
|
end
|
|
21
19
|
end
|
|
22
20
|
end
|
|
@@ -1,24 +1,22 @@
|
|
|
1
1
|
## Country struct
|
|
2
2
|
## Used when syncing geodata with GDS
|
|
3
|
-
## See [[Gdsapi::
|
|
3
|
+
## See [[Gdsapi::Methods::GetLocations]] for details
|
|
4
4
|
## Also see [http://demo.gillbus.com/v2/doc.html#получение-географии-получение-населенных-пунктов-get] for schema definition
|
|
5
5
|
module Gdsapi
|
|
6
|
-
module
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
attribute :attributes, Attributes.optional
|
|
6
|
+
module Structs
|
|
7
|
+
class Location < ::Dry::Struct
|
|
8
|
+
attribute :id, Structs::Coercible::Int
|
|
9
|
+
attribute :name, Structs::Coercible::String
|
|
10
|
+
attribute :latitude, Structs::Coercible::Float
|
|
11
|
+
attribute :longitude, Structs::Coercible::Float
|
|
12
|
+
attribute :parent, Parent.optional
|
|
13
|
+
attribute :type, Type.optional
|
|
14
|
+
attribute :sub_type, Type.optional
|
|
15
|
+
attribute :attributes, Attributes.optional
|
|
17
16
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
end
|
|
17
|
+
def attribute_by_id(id)
|
|
18
|
+
if attributes && id
|
|
19
|
+
attributes.find {|attribute| attribute.id == id}
|
|
22
20
|
end
|
|
23
21
|
end
|
|
24
22
|
end
|
data/lib/gdsapi/structs/point.rb
CHANGED
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
## Point struct
|
|
2
2
|
## Used when syncing geodata with GDS
|
|
3
|
-
## See [[Gdsapi::
|
|
3
|
+
## See [[Gdsapi::Methods::GetPoints]] for details
|
|
4
4
|
## Also see [http://demo.gillbus.com/v2/doc.html#получение-географии-получение-списка-остановок-get] for schema definition
|
|
5
5
|
module Gdsapi
|
|
6
|
-
module
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
attribute :address, Structs::Coercible::String
|
|
15
|
-
end
|
|
6
|
+
module Structs
|
|
7
|
+
class Point < ::Dry::Struct
|
|
8
|
+
attribute :id, Structs::Coercible::Int
|
|
9
|
+
attribute :name, Structs::Coercible::String
|
|
10
|
+
attribute :latitude, Structs::Coercible::Float
|
|
11
|
+
attribute :longitude, Structs::Coercible::Float
|
|
12
|
+
attribute :parent, Parent.optional
|
|
13
|
+
attribute :address, Structs::Coercible::String
|
|
16
14
|
end
|
|
17
15
|
end
|
|
18
16
|
end
|
data/lib/gdsapi/structs.rb
CHANGED
|
@@ -3,17 +3,15 @@ require 'dry-struct'
|
|
|
3
3
|
## This package is used to declare struct types expected from GDS
|
|
4
4
|
## dry-struct is used in order to provide type definitions and flexible coercions mechanism
|
|
5
5
|
module Gdsapi
|
|
6
|
-
module
|
|
7
|
-
module
|
|
8
|
-
include Dry::Types.module
|
|
6
|
+
module Structs
|
|
7
|
+
include Dry::Types.module
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
Attributes = Structs::Array.member(Structs::Hash.symbolized(id: Structs::Coercible::Int,
|
|
10
|
+
name: Structs::Coercible::String,
|
|
11
|
+
values: Structs::Array.member(Structs::Coercible::String)))
|
|
13
12
|
|
|
14
|
-
|
|
13
|
+
Type = Structs::Hash.symbolized(id: Structs::Coercible::Int, name: Structs::Coercible::String)
|
|
15
14
|
|
|
16
|
-
|
|
17
|
-
end
|
|
15
|
+
Parent = Structs::Hash.symbolized(id: Structs::Coercible::Int)
|
|
18
16
|
end
|
|
19
17
|
end
|
data/lib/gdsapi/version.rb
CHANGED
data/lib/gdsapi.rb
CHANGED
|
@@ -3,20 +3,18 @@ Dir[File.expand_path('gdsapi/**/*.rb', __dir__)].each { |file| require file }
|
|
|
3
3
|
# This provides core package manifesto
|
|
4
4
|
## Possible error definitions are provided here
|
|
5
5
|
module Gdsapi
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
class MalformedGdsResponse < GdsError ; end
|
|
21
|
-
end
|
|
6
|
+
# Error thrown on something done wrong on request-side
|
|
7
|
+
class BadRequestError < StandardError ; end
|
|
8
|
+
# Error thrown on 401 from GDS
|
|
9
|
+
class UnathorizedError < BadRequestError ; end
|
|
10
|
+
# Error thrown on 404 from GDS
|
|
11
|
+
class NotFoundError < BadRequestError ; end
|
|
12
|
+
# Error thrown when something is weird with GDS
|
|
13
|
+
class GdsError < StandardError ; end
|
|
14
|
+
# Error thrown when Gds returned server-side exception
|
|
15
|
+
class GdsInternalError < GdsError ; end
|
|
16
|
+
# Error thrown when GDS returned sudden redirect
|
|
17
|
+
class GdsRedirectError < GdsError ; end
|
|
18
|
+
# Error thrown when GDS returned somewhat invalid
|
|
19
|
+
class MalformedGdsResponse < GdsError ; end
|
|
22
20
|
end
|