arbetsformedlingen 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +6 -0
- data/.ruby-style-guide.yml +270 -0
- data/.travis.yml +0 -1
- data/CHANGELOG.md +12 -0
- data/Gemfile +2 -0
- data/LICENSE.txt +1 -1
- data/README.md +1 -1
- data/Rakefile +2 -0
- data/arbetsformedlingen.gemspec +10 -9
- data/bin/console +1 -0
- data/lib/arbetsformedlingen/api/client.rb +48 -30
- data/lib/arbetsformedlingen/api/ledigtarbete_client.rb +6 -1
- data/lib/arbetsformedlingen/api/matchning_client.rb +16 -10
- data/lib/arbetsformedlingen/api/request.rb +10 -13
- data/lib/arbetsformedlingen/api/response.rb +71 -0
- data/lib/arbetsformedlingen/api/results/ad_result.rb +36 -18
- data/lib/arbetsformedlingen/api/results/matchning_result.rb +42 -3
- data/lib/arbetsformedlingen/api/results/soklista_result.rb +16 -2
- data/lib/arbetsformedlingen/api/soap_request.rb +11 -10
- data/lib/arbetsformedlingen/api/values/ad_result_values.rb +6 -1
- data/lib/arbetsformedlingen/api/values/create_ad_page.rb +3 -1
- data/lib/arbetsformedlingen/api/values/matchning_result_values.rb +9 -1
- data/lib/arbetsformedlingen/api/values/soklista_values.rb +17 -1
- data/lib/arbetsformedlingen/api/ws_occupation_client.rb +26 -1
- data/lib/arbetsformedlingen/codes/country_code.rb +3 -1
- data/lib/arbetsformedlingen/codes/drivers_license_code.rb +6 -3
- data/lib/arbetsformedlingen/codes/experience_required_code.rb +3 -1
- data/lib/arbetsformedlingen/codes/municipality_code.rb +3 -1
- data/lib/arbetsformedlingen/codes/occupation_code.rb +3 -1
- data/lib/arbetsformedlingen/codes/salary_type_code.rb +3 -1
- data/lib/arbetsformedlingen/key_struct.rb +5 -3
- data/lib/arbetsformedlingen/models/application_method.rb +3 -1
- data/lib/arbetsformedlingen/models/company.rb +2 -2
- data/lib/arbetsformedlingen/models/document.rb +4 -2
- data/lib/arbetsformedlingen/models/dry/predicates.rb +2 -0
- data/lib/arbetsformedlingen/models/dry/types.rb +5 -3
- data/lib/arbetsformedlingen/models/model.rb +2 -0
- data/lib/arbetsformedlingen/models/packet.rb +3 -1
- data/lib/arbetsformedlingen/models/packet_xml_builder.rb +8 -3
- data/lib/arbetsformedlingen/models/position.rb +5 -3
- data/lib/arbetsformedlingen/models/publication.rb +3 -1
- data/lib/arbetsformedlingen/models/qualification.rb +3 -1
- data/lib/arbetsformedlingen/models/salary.rb +3 -1
- data/lib/arbetsformedlingen/models/schedule.rb +4 -2
- data/lib/arbetsformedlingen/soap_builder.rb +3 -1
- data/lib/arbetsformedlingen/version.rb +3 -1
- metadata +43 -25
@@ -1,13 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'arbetsformedlingen/api/request'
|
2
4
|
require 'arbetsformedlingen/api/values/create_ad_page'
|
3
5
|
|
4
6
|
module Arbetsformedlingen
|
5
7
|
module API
|
8
|
+
# API client for ledigtarbete
|
6
9
|
class LedigtarbeteClient
|
10
|
+
# Base URL for ledigtarbete
|
7
11
|
BASE_URL = 'http://api.arbetsformedlingen.se/ledigtarbete'.freeze
|
8
12
|
|
13
|
+
# HTTP headers
|
9
14
|
HEADERS = {
|
10
|
-
'Content-type' => 'text/xml'
|
15
|
+
'Content-type' => 'text/xml',
|
11
16
|
}.freeze
|
12
17
|
|
13
18
|
# Post ad to API
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'date'
|
2
4
|
require 'time'
|
3
5
|
require 'arbetsformedlingen/api/request'
|
@@ -5,13 +7,16 @@ require 'arbetsformedlingen/api/results/matchning_result'
|
|
5
7
|
|
6
8
|
module Arbetsformedlingen
|
7
9
|
module API
|
10
|
+
# API client for matchning
|
8
11
|
class MatchningClient
|
9
12
|
attr_reader :request
|
10
13
|
|
14
|
+
# Initialize client
|
11
15
|
def initialize(request: Request.new)
|
12
16
|
@request = request
|
13
17
|
end
|
14
18
|
|
19
|
+
# rubocop:disable Metrics/LineLength
|
15
20
|
# Find matching ads from API
|
16
21
|
# @return [MatchningResult] the result.
|
17
22
|
# @param area_id [String] Area ID.
|
@@ -36,6 +41,7 @@ module Arbetsformedlingen
|
|
36
41
|
# client.ads(keywrods: 'ruby', page: 3, page_size: 10)
|
37
42
|
# @example Get ads with keyword and organsiation numer
|
38
43
|
# client.ads(keywrods: 'ruby', organization_number: org_no)
|
44
|
+
# rubocop:enable Metrics/LineLength
|
39
45
|
def ads(
|
40
46
|
# one of these must be present
|
41
47
|
county_id: nil,
|
@@ -55,7 +61,7 @@ module Arbetsformedlingen
|
|
55
61
|
|
56
62
|
one_of_required = [county_id, municipality_id, occupation_id, keywords]
|
57
63
|
if one_of_required.all?(&:nil?)
|
58
|
-
error_message = 'One of: county_id, municipality_id, occupation_id, keywords is required'
|
64
|
+
error_message = 'One of: county_id, municipality_id, occupation_id, keywords is required' # rubocop:disable Metrics/LineLength
|
59
65
|
raise ArgumentError, error_message
|
60
66
|
end
|
61
67
|
|
@@ -77,12 +83,12 @@ module Arbetsformedlingen
|
|
77
83
|
anstallningstyp: santize_employment_type_query(employment_type),
|
78
84
|
yrkesomradeid: occupation_field_id,
|
79
85
|
sokdatum: normalize_date_to_iso8601(published_after),
|
80
|
-
organisationsnummer: organization_number
|
86
|
+
organisationsnummer: organization_number,
|
81
87
|
}
|
82
88
|
|
83
89
|
response = request.get('matchning', query: query)
|
84
90
|
|
85
|
-
MatchningResult.build(response
|
91
|
+
MatchningResult.build(response)
|
86
92
|
end
|
87
93
|
|
88
94
|
private
|
@@ -99,11 +105,11 @@ module Arbetsformedlingen
|
|
99
105
|
end
|
100
106
|
|
101
107
|
def santize_employment_type_query(employment_type)
|
102
|
-
#
|
103
|
-
#
|
108
|
+
# Sökkriterier anställningstyp.
|
109
|
+
# Värdena ska ligga mellan 1 och 3.
|
104
110
|
# 1 är XXX (EJ DOKUMENTERAT)
|
105
|
-
# 2
|
106
|
-
# 3
|
111
|
+
# 2 är somarjobb / feriejobb
|
112
|
+
# 3 är utlandsjobb
|
107
113
|
|
108
114
|
# TODO: The question is what we do if an invalid parameter is passed
|
109
115
|
# should we crash?
|
@@ -113,15 +119,15 @@ module Arbetsformedlingen
|
|
113
119
|
|
114
120
|
def santize_keywords_query(keywords)
|
115
121
|
#
|
116
|
-
#
|
117
|
-
# mellanslag (
|
122
|
+
# Sökord kan separeras eller kombineras med något av följande exempel:
|
123
|
+
# mellanslag (" ")
|
118
124
|
#
|
119
125
|
# [Example]
|
120
126
|
# /matchning?nyckelord="bagare""test"
|
121
127
|
# /matchning?nyckelord="bagare"OR"test" /matchning?nyckelord="automatisk"AND"test"
|
122
128
|
|
123
129
|
# Valid characters
|
124
|
-
#
|
130
|
+
# abcdefghijklmnopqrstuvwxyzåäö0123456789: ,.-"
|
125
131
|
|
126
132
|
# TODO: What do we do if invalid characters are passed? Crash?
|
127
133
|
keywords
|
@@ -1,19 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'uri'
|
2
4
|
require 'net/http'
|
3
5
|
require 'json'
|
6
|
+
require 'arbetsformedlingen/api/response'
|
4
7
|
|
5
8
|
module Arbetsformedlingen
|
6
9
|
module API
|
10
|
+
# API request object
|
7
11
|
class Request
|
8
|
-
Response = KeyStruct.new(:code, :body, :json)
|
9
|
-
|
10
12
|
attr_reader :locale, :base_url
|
11
13
|
|
14
|
+
# Initialize request
|
12
15
|
def initialize(base_url: '', locale: 'sv')
|
13
16
|
@base_url = base_url
|
14
17
|
@locale = locale
|
15
18
|
end
|
16
19
|
|
20
|
+
# Perform GEt request
|
21
|
+
# @param [String] url to be fetched
|
22
|
+
# @param [Hash] query params
|
23
|
+
# @return [Response] response object
|
17
24
|
def get(url, query: {})
|
18
25
|
uri = URI("#{base_url}#{url}?#{URI.encode_www_form(query.to_a)}")
|
19
26
|
|
@@ -25,17 +32,7 @@ module Arbetsformedlingen
|
|
25
32
|
|
26
33
|
response = http.request(request)
|
27
34
|
|
28
|
-
Response.new(
|
29
|
-
code: response.code,
|
30
|
-
body: response.read_body,
|
31
|
-
json: parse_json(response.read_body)
|
32
|
-
)
|
33
|
-
end
|
34
|
-
|
35
|
-
def parse_json(string)
|
36
|
-
JSON.parse(string.to_s)
|
37
|
-
rescue JSON::ParserError => _e
|
38
|
-
{}
|
35
|
+
Response.new(response)
|
39
36
|
end
|
40
37
|
end
|
41
38
|
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'nokogiri'
|
5
|
+
rescue LoadError
|
6
|
+
end
|
7
|
+
|
8
|
+
module Arbetsformedlingen
|
9
|
+
module API
|
10
|
+
# API response object
|
11
|
+
class Response
|
12
|
+
# Initialize response
|
13
|
+
def initialize(response)
|
14
|
+
@response = response
|
15
|
+
@json = nil
|
16
|
+
end
|
17
|
+
|
18
|
+
# True if response is 200
|
19
|
+
# @return [Boolean] true if response code is 200
|
20
|
+
def success?
|
21
|
+
response.code == '200'
|
22
|
+
end
|
23
|
+
|
24
|
+
# Response body
|
25
|
+
# @return [String] the response body
|
26
|
+
def body
|
27
|
+
response.read_body
|
28
|
+
end
|
29
|
+
|
30
|
+
# Response JSON
|
31
|
+
# @return [Hash] response json - empty if JSON is invalid
|
32
|
+
def json
|
33
|
+
@json ||= parse_json(body)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Response XML
|
37
|
+
# @return [Nokogiri::XML::Document] response - empty is XML is invalid
|
38
|
+
def xml
|
39
|
+
@xml ||= parse_xml(body)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Delegate missing values to response
|
43
|
+
def method_missing(method_name, *arguments, &block)
|
44
|
+
if response.respond_to?(method_name)
|
45
|
+
response.public_send(method_name, *arguments, &block)
|
46
|
+
else
|
47
|
+
super
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Return true if missing method can be delegated
|
52
|
+
def respond_to_missing?(method_name, include_private = false)
|
53
|
+
response.respond_to?(method_name) || super
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
attr_reader :response
|
59
|
+
|
60
|
+
def parse_json(string)
|
61
|
+
JSON.parse(string.to_s)
|
62
|
+
rescue JSON::ParserError => _e
|
63
|
+
{}
|
64
|
+
end
|
65
|
+
|
66
|
+
def parse_xml(string)
|
67
|
+
Nokogiri::XML(string).tap(&:remove_namespaces!)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -1,11 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'arbetsformedlingen/api/values/ad_result_values'
|
2
4
|
|
3
5
|
module Arbetsformedlingen
|
4
6
|
module API
|
5
7
|
module AdResult
|
6
|
-
|
7
|
-
|
8
|
+
# Build API result object for ad result
|
9
|
+
# @param [API::Response] response
|
10
|
+
# @return [Values::Ad]
|
11
|
+
def self.build(response)
|
12
|
+
return build_empty(response) unless response.success?
|
13
|
+
|
14
|
+
build_page(response)
|
15
|
+
end
|
8
16
|
|
17
|
+
# private
|
18
|
+
|
19
|
+
def self.build_page(response)
|
20
|
+
response_data = response.json
|
21
|
+
data = response_data.fetch('platsannons')
|
9
22
|
ad_data = data.fetch('annons')
|
10
23
|
|
11
24
|
Values::Ad.new(
|
@@ -19,32 +32,37 @@ module Arbetsformedlingen
|
|
19
32
|
total_vacancies: ad_data.fetch('antal_platser'),
|
20
33
|
municipalities: ad_data.fetch('kommunnamn'),
|
21
34
|
municipality_id: ad_data.fetch('kommunkod'),
|
22
|
-
total_vacancies_with_visa: ad_data.fetch('antalplatserVisa'),
|
35
|
+
total_vacancies_with_visa: ad_data.fetch('antalplatserVisa', nil),
|
23
36
|
employment_type: ad_data.fetch('anstallningstyp'),
|
24
37
|
terms: build_terms(data.fetch('villkor')),
|
25
38
|
application: build_application(data.fetch('ansokan')),
|
26
39
|
workplace: build_workplace(data.fetch('arbetsplats')),
|
27
|
-
requirements: build_requirements(data.fetch('krav'))
|
40
|
+
requirements: build_requirements(data.fetch('krav')),
|
41
|
+
response: response
|
28
42
|
)
|
29
43
|
end
|
30
44
|
|
45
|
+
def self.build_empty(response)
|
46
|
+
Values::Ad.new(response: response)
|
47
|
+
end
|
48
|
+
|
31
49
|
def self.build_terms(data)
|
32
50
|
Values::Terms.new(
|
33
|
-
duration: data.fetch('varaktighet'),
|
34
|
-
working_hours: data.fetch('arbetstid'),
|
35
|
-
working_hours_description: data.fetch('arbetstidvaraktighet'),
|
51
|
+
duration: data.fetch('varaktighet', nil),
|
52
|
+
working_hours: data.fetch('arbetstid', nil),
|
53
|
+
working_hours_description: data.fetch('arbetstidvaraktighet', nil),
|
36
54
|
salary_type: data.fetch('lonetyp'),
|
37
|
-
salary_form: data.fetch('loneform')
|
55
|
+
salary_form: data.fetch('loneform', nil)
|
38
56
|
)
|
39
57
|
end
|
40
58
|
|
41
59
|
def self.build_application(data)
|
42
60
|
Values::Application.new(
|
43
61
|
reference: data['referens'],
|
44
|
-
application_url: data.fetch('webbplats'),
|
62
|
+
application_url: data.fetch('webbplats', nil),
|
45
63
|
email: data['epostadress'],
|
46
64
|
last_application_at: data.fetch('sista_ansokningsdag', nil),
|
47
|
-
application_comment: data.fetch('ovrigt_om_ansokan')
|
65
|
+
application_comment: data.fetch('ovrigt_om_ansokan', nil)
|
48
66
|
)
|
49
67
|
end
|
50
68
|
|
@@ -53,11 +71,11 @@ module Arbetsformedlingen
|
|
53
71
|
name: data.fetch('arbetsplatsnamn'),
|
54
72
|
postal: build_postal(data),
|
55
73
|
country: data.fetch('land'),
|
56
|
-
visit_address: data.fetch('besoksadress'),
|
57
|
-
logotype_url: data.fetch('logotypurl'),
|
58
|
-
website: data.fetch('hemsida'),
|
74
|
+
visit_address: data.fetch('besoksadress', nil),
|
75
|
+
logotype_url: data.fetch('logotypurl', nil),
|
76
|
+
website: data.fetch('hemsida', nil),
|
59
77
|
contacts: (
|
60
|
-
data.dig('kontaktpersonlista', '
|
78
|
+
data.dig('kontaktpersonlista', 'kontaktpersondata') || []
|
61
79
|
).map do |contact_data|
|
62
80
|
build_workplace_contacts(contact_data)
|
63
81
|
end
|
@@ -66,10 +84,10 @@ module Arbetsformedlingen
|
|
66
84
|
|
67
85
|
def self.build_postal(data)
|
68
86
|
Values::Postal.new(
|
69
|
-
code: data.fetch('postnummer'),
|
70
|
-
address: data.fetch('postadress'),
|
71
|
-
city: data.fetch('postort'),
|
72
|
-
country: data.fetch('postland')
|
87
|
+
code: data.fetch('postnummer', nil),
|
88
|
+
address: data.fetch('postadress', nil),
|
89
|
+
city: data.fetch('postort', nil),
|
90
|
+
country: data.fetch('postland', nil)
|
73
91
|
)
|
74
92
|
end
|
75
93
|
|
@@ -1,9 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'arbetsformedlingen/api/values/matchning_result_values'
|
2
4
|
|
3
5
|
module Arbetsformedlingen
|
4
6
|
module API
|
5
7
|
module MatchningResult
|
6
|
-
|
8
|
+
# Build API result object for matchning result
|
9
|
+
# @param [API::Response] response
|
10
|
+
# @return [Values::MatchningPage]
|
11
|
+
def self.build(response)
|
12
|
+
return empty_matchning_page(response) unless response.success?
|
13
|
+
|
14
|
+
build_matchning_page(response)
|
15
|
+
end
|
16
|
+
|
17
|
+
# private
|
18
|
+
|
19
|
+
def self.empty_matchning_page(response)
|
20
|
+
response_data = response.json
|
21
|
+
|
22
|
+
Values::MatchningPage.new(
|
23
|
+
list_name: 'annonser',
|
24
|
+
total_ads: 0,
|
25
|
+
total_ads_exact: 0,
|
26
|
+
total_ads_nearby: 0,
|
27
|
+
total_vacancies_on_page: 0,
|
28
|
+
total_pages: 0,
|
29
|
+
raw_data: response_data,
|
30
|
+
data: [],
|
31
|
+
response: response
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.build_matchning_page(response)
|
36
|
+
response_data = response.json
|
7
37
|
data = response_data.fetch('matchningslista')
|
8
38
|
|
9
39
|
Values::MatchningPage.new(
|
@@ -14,10 +44,19 @@ module Arbetsformedlingen
|
|
14
44
|
total_vacancies_on_page: data.fetch('antal_platserTotal'),
|
15
45
|
total_pages: data.fetch('antal_sidor'),
|
16
46
|
raw_data: response_data,
|
17
|
-
data: data
|
47
|
+
data: build_ad_results(data),
|
48
|
+
response: response
|
18
49
|
)
|
19
50
|
end
|
20
51
|
|
52
|
+
# private
|
53
|
+
|
54
|
+
def self.build_ad_results(data)
|
55
|
+
data.fetch('matchningdata', []).map do |ad_data|
|
56
|
+
build_ad_result(ad_data)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
21
60
|
def self.build_ad_result(ad_data)
|
22
61
|
Values::MatchningAd.new(
|
23
62
|
id: ad_data.fetch('annonsid'),
|
@@ -32,7 +71,7 @@ module Arbetsformedlingen
|
|
32
71
|
url: ad_data.fetch('annonsurl'),
|
33
72
|
relevance: ad_data.fetch('relevans'),
|
34
73
|
total_vacancies: ad_data.fetch('antalplatser'),
|
35
|
-
total_vacancies_with_visa: ad_data.fetch('antalPlatserVisa'),
|
74
|
+
total_vacancies_with_visa: ad_data.fetch('antalPlatserVisa', nil),
|
36
75
|
duration_id: ad_data.fetch('varaktighetId', nil),
|
37
76
|
counties: ad_data.fetch('lan'),
|
38
77
|
country_id: ad_data.fetch('lanid'),
|
@@ -1,9 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'arbetsformedlingen/api/values/soklista_values'
|
2
4
|
|
3
5
|
module Arbetsformedlingen
|
4
6
|
module API
|
5
7
|
module SoklistaResult
|
6
|
-
|
8
|
+
# Build API result object for "soklista"
|
9
|
+
# @param [API::Response] response
|
10
|
+
# @param list_name [String] result list name
|
11
|
+
# @return [Values::SoklistaPage]
|
12
|
+
def self.build(response, list_name: nil)
|
13
|
+
build_page(response, list_name)
|
14
|
+
end
|
15
|
+
|
16
|
+
# private
|
17
|
+
|
18
|
+
def self.build_page(response, list_name)
|
19
|
+
response_data = response.json
|
7
20
|
data = response_data.fetch('soklista', {})
|
8
21
|
|
9
22
|
Values::SoklistaPage.new(
|
@@ -13,7 +26,8 @@ module Arbetsformedlingen
|
|
13
26
|
raw_data: response_data,
|
14
27
|
data: data.fetch('sokdata', []).map do |result|
|
15
28
|
build_search_result(result)
|
16
|
-
end
|
29
|
+
end,
|
30
|
+
response: response
|
17
31
|
)
|
18
32
|
end
|
19
33
|
|
@@ -1,5 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'uri'
|
2
4
|
require 'net/http'
|
5
|
+
require 'arbetsformedlingen/api/response'
|
3
6
|
|
4
7
|
begin
|
5
8
|
require 'nokogiri'
|
@@ -8,11 +11,14 @@ end
|
|
8
11
|
|
9
12
|
module Arbetsformedlingen
|
10
13
|
module API
|
14
|
+
# API SOAP request
|
11
15
|
class SOAPRequest
|
12
|
-
|
16
|
+
# SOAP response
|
17
|
+
# Response = KeyStruct.new(:code, :body, :xml)
|
13
18
|
|
14
19
|
attr_reader :locale, :uri, :url
|
15
20
|
|
21
|
+
# Initialize SOAP request
|
16
22
|
def initialize(url, locale: nil)
|
17
23
|
unless Object.const_defined?(:Nokogiri)
|
18
24
|
raise(ArgumentError, "unable to require 'nokogiri' gem, please install it")
|
@@ -23,6 +29,9 @@ module Arbetsformedlingen
|
|
23
29
|
@locale = locale
|
24
30
|
end
|
25
31
|
|
32
|
+
# Performs a POST request
|
33
|
+
# @param [String] the post body
|
34
|
+
# @return [Response] the response
|
26
35
|
def post(body)
|
27
36
|
http = Net::HTTP.new(uri.host, uri.port)
|
28
37
|
http.use_ssl = true if uri.scheme == 'https'
|
@@ -34,15 +43,7 @@ module Arbetsformedlingen
|
|
34
43
|
|
35
44
|
response = http.request(request)
|
36
45
|
|
37
|
-
Response.new(
|
38
|
-
code: response.code,
|
39
|
-
body: response.read_body,
|
40
|
-
xml: parse_xml(response.read_body)
|
41
|
-
)
|
42
|
-
end
|
43
|
-
|
44
|
-
def parse_xml(string)
|
45
|
-
Nokogiri::XML(string).tap { |doc| doc.remove_namespaces! }
|
46
|
+
Response.new(response)
|
46
47
|
end
|
47
48
|
end
|
48
49
|
end
|