ns-yapi 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 9a0c3a195f10cd241f4f0a772e6847aadf53aae8
4
- data.tar.gz: cf8b58cafe9440992ce191c11a2e13fd8216e695
2
+ SHA256:
3
+ metadata.gz: 90e0e28a27c5819ad9ccab28567b1645e19995308e2da96345f0ef7dcb2fdff7
4
+ data.tar.gz: b815628df8eb973f22856ca0d95c9575e2bc02749225bb95685b622bdabe5c9c
5
5
  SHA512:
6
- metadata.gz: 667f33d89852136b0b0ceaafe689d2cd35bbb1988abb4f01601b9f52da84096b3a12300f96d0ddb5a2a54d3548ce65c6856098ca9d23ddba635ff6513b9f8efd
7
- data.tar.gz: d0987af5c7c1449ac9d6e10db022e686af030e55004a11f2084ebd70de32c8fd2356289e7216eeda38c37bd4c38c17dae8644be14f28ab55aa65531cb91cfb87
6
+ metadata.gz: 5da72d6d6be93450f0d7c84aae840719df990e26d9253250bf53fc564431f1127fb606292757fef8ef943650b5eb84834b30ca24222be6cbe5e72f83893676a6
7
+ data.tar.gz: 6bb0a08ac0d239b3fba39e62c094bc207f08c171b9ef3a83e739eefc91078e6fec1ff3045d7dfab95fdda435450f0399b70d102129f88044e288533f90c36b47
data/.rubocop.yml ADDED
@@ -0,0 +1,19 @@
1
+ require: rubocop-performance
2
+
3
+ Style/Documentation:
4
+ Enabled: false
5
+
6
+ Metrics/LineLength:
7
+ Max: 120
8
+ Exclude:
9
+ - spec/**/*
10
+
11
+ Metrics/BlockLength:
12
+ Exclude:
13
+ - spec/**/*
14
+
15
+ Metrics/MethodLength:
16
+ Max: 20
17
+
18
+ Metrics/ClassLength:
19
+ Max: 200
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.1.2
1
+ 2.6.2
data/.travis.yml CHANGED
@@ -1,4 +1,7 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 1.9.3
4
- - 2.2.2
3
+ - 2.6.2
4
+
5
+ script:
6
+ - bundle exec rubocop
7
+ - bundle exec rspec
data/Gemfile CHANGED
@@ -1,15 +1,23 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source 'http://rubygems.org'
2
4
 
3
- gem "httpclient", "~> 2.3.3"
4
5
  gem 'rake'
6
+ gem 'rest-client'
5
7
 
6
8
  gemspec
7
9
 
8
10
  group :test do
11
+ gem 'coveralls', require: false
12
+ gem 'mocha', require: 'mocha/api'
13
+ gem 'pry'
9
14
  gem 'rspec'
10
15
  gem 'simplecov'
11
- gem "webmock", "~> 1.11.0"
12
- gem "timecop", "~> 0.6.1"
13
- gem 'mocha', require: 'mocha/api'
14
- gem 'coveralls', require: false
16
+ gem 'timecop'
17
+ gem 'webmock'
18
+ end
19
+
20
+ group :development do
21
+ gem 'rubocop', require: false
22
+ gem 'rubocop-performance', require: false
15
23
  end
data/Gemfile.lock CHANGED
@@ -3,69 +3,120 @@ PATH
3
3
  specs:
4
4
  ns-yapi (0.5.0)
5
5
  addressable
6
- httpclient
7
6
  nokogiri
8
7
  nori
8
+ rest-client
9
9
 
10
10
  GEM
11
11
  remote: http://rubygems.org/
12
12
  specs:
13
- addressable (2.3.4)
14
- colorize (0.5.8)
15
- coveralls (0.6.7)
16
- colorize
17
- multi_json (~> 1.3)
18
- rest-client
19
- simplecov (>= 0.7)
20
- thor
21
- crack (0.4.0)
22
- safe_yaml (~> 0.9.0)
23
- diff-lcs (1.2.4)
24
- httpclient (2.3.3)
25
- metaclass (0.0.1)
26
- mime-types (1.23)
27
- mini_portile2 (2.3.0)
28
- mocha (0.14.0)
13
+ addressable (2.6.0)
14
+ public_suffix (>= 2.0.2, < 4.0)
15
+ ast (2.4.0)
16
+ coderay (1.1.2)
17
+ coveralls (0.8.22)
18
+ json (>= 1.8, < 3)
19
+ simplecov (~> 0.16.1)
20
+ term-ansicolor (~> 1.3)
21
+ thor (~> 0.19.4)
22
+ tins (~> 1.6)
23
+ crack (0.4.3)
24
+ safe_yaml (~> 1.0.0)
25
+ diff-lcs (1.3)
26
+ docile (1.3.1)
27
+ domain_name (0.5.20180417)
28
+ unf (>= 0.0.5, < 1.0.0)
29
+ hashdiff (0.3.8)
30
+ http-cookie (1.0.3)
31
+ domain_name (~> 0.5)
32
+ jaro_winkler (1.5.2)
33
+ json (2.2.0)
34
+ metaclass (0.0.4)
35
+ method_source (0.9.2)
36
+ mime-types (3.2.2)
37
+ mime-types-data (~> 3.2015)
38
+ mime-types-data (3.2019.0331)
39
+ mini_portile2 (2.4.0)
40
+ mocha (1.8.0)
29
41
  metaclass (~> 0.0.1)
30
- multi_json (1.7.7)
31
- nokogiri (1.8.1)
32
- mini_portile2 (~> 2.3.0)
42
+ netrc (0.11.0)
43
+ nokogiri (1.10.2)
44
+ mini_portile2 (~> 2.4.0)
33
45
  nori (2.6.0)
34
- rake (10.0.3)
35
- rest-client (1.6.7)
36
- mime-types (>= 1.16)
37
- rspec (2.13.0)
38
- rspec-core (~> 2.13.0)
39
- rspec-expectations (~> 2.13.0)
40
- rspec-mocks (~> 2.13.0)
41
- rspec-core (2.13.1)
42
- rspec-expectations (2.13.0)
43
- diff-lcs (>= 1.1.3, < 2.0)
44
- rspec-mocks (2.13.1)
45
- safe_yaml (0.9.3)
46
- simplecov (0.7.1)
47
- multi_json (~> 1.0)
48
- simplecov-html (~> 0.7.1)
49
- simplecov-html (0.7.1)
50
- thor (0.18.1)
51
- timecop (0.6.1)
52
- webmock (1.11.0)
53
- addressable (>= 2.2.7)
46
+ parallel (1.17.0)
47
+ parser (2.6.2.1)
48
+ ast (~> 2.4.0)
49
+ pry (0.12.2)
50
+ coderay (~> 1.1.0)
51
+ method_source (~> 0.9.0)
52
+ psych (3.1.0)
53
+ public_suffix (3.0.3)
54
+ rainbow (3.0.0)
55
+ rake (12.3.2)
56
+ rest-client (2.0.2)
57
+ http-cookie (>= 1.0.2, < 2.0)
58
+ mime-types (>= 1.16, < 4.0)
59
+ netrc (~> 0.8)
60
+ rspec (3.8.0)
61
+ rspec-core (~> 3.8.0)
62
+ rspec-expectations (~> 3.8.0)
63
+ rspec-mocks (~> 3.8.0)
64
+ rspec-core (3.8.0)
65
+ rspec-support (~> 3.8.0)
66
+ rspec-expectations (3.8.2)
67
+ diff-lcs (>= 1.2.0, < 2.0)
68
+ rspec-support (~> 3.8.0)
69
+ rspec-mocks (3.8.0)
70
+ diff-lcs (>= 1.2.0, < 2.0)
71
+ rspec-support (~> 3.8.0)
72
+ rspec-support (3.8.0)
73
+ rubocop (0.67.2)
74
+ jaro_winkler (~> 1.5.1)
75
+ parallel (~> 1.10)
76
+ parser (>= 2.5, != 2.5.1.1)
77
+ psych (>= 3.1.0)
78
+ rainbow (>= 2.2.2, < 4.0)
79
+ ruby-progressbar (~> 1.7)
80
+ unicode-display_width (>= 1.4.0, < 1.6)
81
+ rubocop-performance (1.1.0)
82
+ rubocop (>= 0.67.0)
83
+ ruby-progressbar (1.10.0)
84
+ safe_yaml (1.0.5)
85
+ simplecov (0.16.1)
86
+ docile (~> 1.1)
87
+ json (>= 1.8, < 3)
88
+ simplecov-html (~> 0.10.0)
89
+ simplecov-html (0.10.2)
90
+ term-ansicolor (1.7.1)
91
+ tins (~> 1.0)
92
+ thor (0.19.4)
93
+ timecop (0.9.1)
94
+ tins (1.20.2)
95
+ unf (0.1.4)
96
+ unf_ext
97
+ unf_ext (0.0.7.5)
98
+ unicode-display_width (1.5.0)
99
+ webmock (3.5.1)
100
+ addressable (>= 2.3.6)
54
101
  crack (>= 0.3.2)
102
+ hashdiff
55
103
 
56
104
  PLATFORMS
57
105
  ruby
58
106
 
59
107
  DEPENDENCIES
60
108
  coveralls
61
- httpclient (~> 2.3.3)
62
109
  mocha
63
110
  ns-yapi!
111
+ pry
64
112
  rake
113
+ rest-client
65
114
  rspec
115
+ rubocop
116
+ rubocop-performance
66
117
  simplecov
67
- timecop (~> 0.6.1)
68
- webmock (~> 1.11.0)
118
+ timecop
119
+ webmock
69
120
 
70
121
  BUNDLED WITH
71
- 1.16.0
122
+ 1.17.2
@@ -1,13 +1,15 @@
1
- class PricesUrl
1
+ # frozen_string_literal: true
2
2
 
3
+ class PricesUrl
3
4
  def initialize(url)
4
- raise InvalidURL, "You must give an url, ie http://www.ns.nl/api" unless url
5
+ raise InvalidURL, 'You must give an url, ie http://www.ns.nl/api' unless url
6
+
5
7
  @url = url
6
8
  end
7
9
 
8
- def url (opts = {date: nil, from: "", to: ""})
9
- opts[:date] = opts[:date].strftime("%d%m%Y") if opts[:date]
10
- uri = URI.escape(opts.collect{|k,v| "#{k}=#{v}"}.join('&'))
10
+ def url(opts = { date: nil, from: '', to: '' })
11
+ opts[:date] = opts[:date].strftime('%d%m%Y') if opts[:date]
12
+ uri = Addressable::URI.escape(opts.collect { |k, v| "#{k}=#{v}" }.join('&'))
11
13
  "#{@url}?#{uri}"
12
14
  end
13
15
 
data/lib/ns_client.rb CHANGED
@@ -1,191 +1,219 @@
1
- #encoding: utf-8
1
+ # frozen_string_literal: true
2
+
2
3
  require 'pathname'
3
4
  require 'time'
4
5
  require 'nori'
5
6
  require 'nokogiri'
6
- require 'httpclient'
7
- require "addressable/uri"
7
+ require 'rest-client'
8
+ require 'addressable/uri'
8
9
 
9
10
  this = Pathname.new(__FILE__).realpath
10
- lib_path = File.expand_path("..", this)
11
- $:.unshift(lib_path)
12
-
13
- $ROOT = File.expand_path("../", lib_path)
11
+ lib_path = File.expand_path('..', this)
12
+ $LOAD_PATH.unshift(lib_path)
14
13
 
15
14
  Dir.glob(File.join(lib_path, '/**/*.rb')).each do |file|
16
15
  require file
17
16
  end
18
17
 
19
18
  module NSYapi
20
-
21
19
  class Configuration
22
- attr_accessor :username, :password
20
+ attr_accessor :username, :password, :configuration
23
21
  end
24
22
 
25
23
  def self.configure(configuration = NSYapi::Configuration.new)
26
24
  yield configuration if block_given?
27
- @@configuration = configuration
25
+ @configuration = configuration
28
26
  end
29
27
 
30
28
  def self.configuration # :nodoc:
31
- @@configuration ||= NSYapi::Configuration.new
29
+ @configuration ||= NSYapi::Configuration.new
32
30
  end
33
31
 
34
32
  def self.client
35
- @client_instance = NSClient.new(configuration.username, configuration.password) unless @client_instance
33
+ @client_instance ||= NSClient.new(configuration.username, configuration.password)
36
34
  @client_instance
37
35
  end
38
-
39
36
  end
40
37
 
41
38
  class NSClient
42
-
43
- attr_accessor :last_received_raw_xml, :last_received_corrected_xml
39
+ attr_accessor :last_received_raw_xml, :last_received_corrected_xml, :username, :password
44
40
 
45
41
  def initialize(username, password)
46
- @client = HTTPClient.new
47
- @client.set_auth("http://webservices.ns.nl", username, password)
48
- @prices_url = PricesUrl.new("http://webservices.ns.nl/ns-api-prijzen-v3")
49
- @last_received_raw_xml = ""
50
- @last_received_corrected_xml = ""
42
+ @username = username
43
+ @password = password
44
+ @prices_url = PricesUrl.new('https://webservices.ns.nl/ns-api-prijzen-v3')
45
+ @last_received_raw_xml = ''
46
+ @last_received_corrected_xml = ''
51
47
  end
52
48
 
53
49
  def stations
54
- parse_stations(get_xml("http://webservices.ns.nl/ns-api-stations-v2"))
50
+ parse_stations(get_xml('https://webservices.ns.nl/ns-api-stations-v2'))
55
51
  end
56
52
 
57
53
  def stations_short
58
- parse_stations_as_map(get_xml("http://webservices.ns.nl/ns-api-stations-v2"))
54
+ parse_stations_as_map(get_xml('https://webservices.ns.nl/ns-api-stations-v2'))
59
55
  end
60
56
 
61
- def disruptions (query = nil)
57
+ def disruptions(query = nil)
62
58
  response_xml = get_xml(disruption_url(query))
63
59
  raise_error_when_response_is_error(response_xml)
64
60
  parse_disruptions(response_xml)
65
61
  end
66
62
 
67
- def prices (opts = {from: nil, to: nil, via: nil, date: nil})
68
- raise MissingParameter, "from and to station is required" if (opts[:from] == nil && opts[:to] == nil)
69
- raise MissingParameter, "from station is required" unless opts[:from]
70
- raise MissingParameter, "to station is required" unless opts[:to]
71
- raise SameDestinationError,
72
- "from (#{opts[:from]}) and to (#{opts[:to]}) parameters should not be equal" if opts[:from] == opts[:to]
63
+ def prices(opts = { from: nil, to: nil, via: nil, date: nil })
64
+ validate_prices(opts)
73
65
  response_xml = get_xml(@prices_url.url(opts))
74
66
  raise_error_when_response_is_error(response_xml)
75
67
  parse_prices(response_xml)
76
68
  end
77
69
 
70
+ def validate_price_parameters(opts)
71
+ raise MissingParameter, 'from and to station is required' if opts[:from].nil? && opts[:to].nil?
72
+ raise MissingParameter, 'from station is required' unless opts[:from]
73
+ raise MissingParameter, 'to station is required' unless opts[:to]
74
+ end
75
+
76
+ def validate_prices(opts)
77
+ validate_price_parameters(opts)
78
+
79
+ return unless opts[:from] == opts[:to]
80
+
81
+ raise SameDestinationError,
82
+ "from (#{opts[:from]}) and to (#{opts[:to]}) parameters should not be equal"
83
+ end
84
+
78
85
  def parse_prices(response_xml)
79
86
  prices_response = PricesResponse.new
80
- (response_xml/'/VervoerderKeuzes/VervoerderKeuze').each do |transporter|
81
- prices_response.tariff_units = (transporter/'./Tariefeenheden').text.to_i
82
-
83
- (transporter/'ReisType').each do |travel_type|
84
- prices = []
85
-
86
- (travel_type/'ReisKlasse').each do |travel_class|
87
- (travel_class/'Korting/Kortingsprijs').each do |price_element|
88
- product_price = ProductPrice.new
89
- product_price.discount = price_element.attr("name")
90
- product_price.train_class = travel_class.attr("klasse")
91
- product_price.amount = price_element.attr("prijs").gsub(",", ".").to_f
92
- prices << product_price
93
- end
94
- end
87
+ (response_xml / '/VervoerderKeuzes/VervoerderKeuze').each do |transporter|
88
+ prices_response.tariff_units = (transporter / './Tariefeenheden').text.to_i
89
+
90
+ (transporter / 'ReisType').each do |travel_type|
91
+ prices = parse_travel_type(travel_type)
95
92
 
96
93
  name = travel_type.attr('name')
97
94
  prices_response.products[name] = prices
98
95
  end
99
-
100
96
  end
101
97
  prices_response
102
98
  end
103
99
 
100
+ def parse_travel_type(travel_type)
101
+ prices = []
102
+
103
+ (travel_type / 'ReisKlasse').each do |travel_class|
104
+ (travel_class / 'Korting/Kortingsprijs').each do |price_element|
105
+ product_price = ProductPrice.new
106
+ product_price.discount = price_element.attr('name')
107
+ product_price.train_class = travel_class.attr('klasse')
108
+ product_price.amount = price_element.attr('prijs').tr(',', '.').to_f
109
+ prices << product_price
110
+ end
111
+ end
112
+
113
+ prices
114
+ end
115
+
104
116
  def parse_stations(response_xml)
105
117
  result = []
106
- (response_xml/'/Stations/Station').each do |station|
107
- s = Station.new
108
- s.code = (station/'./Code').text
109
- s.type = (station/'./Type').text
110
- s.country = (station/'./Land').text
111
- s.short_name = (station/'./Namen/Kort').text
112
- s.name = (station/'./Namen/Middel').text
113
- s.long_name = (station/'./Namen/Lang').text
114
- s.lat = (station/'./Lat').text
115
- s.long = (station/'./Lon').text
116
- s.uiccode = (station/'./UICCode').text
117
- result << s
118
+ (response_xml / '/Stations/Station').each do |station|
119
+ result << parse_station(station)
118
120
  end
119
121
  result
120
122
  end
121
123
 
124
+ def parse_station(station)
125
+ s = Station.new
126
+ s.code = parse_station_field(station, './Code')
127
+ s.type = parse_station_field(station, './Type')
128
+ s.country = parse_station_field(station, './Land')
129
+ s.short_name = parse_station_field(station, './Namen/Kort')
130
+ s.name = parse_station_field(station, './Namen/Middel')
131
+ s.long_name = parse_station_field(station, './Namen/Lang')
132
+ s.lat = parse_station_field(station, './Lat')
133
+ s.long = parse_station_field(station, './Lon')
134
+ s.uiccode = parse_station_field(station, './UICCode')
135
+ s
136
+ end
137
+
138
+ def parse_station_field(station, field)
139
+ (station / field).text
140
+ end
141
+
122
142
  def parse_stations_as_map(response_xml)
123
143
  result = {}
124
- (response_xml/'/Stations/Station').each do |station|
125
- code = (station/'./Code').text
126
- name = (station/'./Namen/Middel').text
127
- country = (station/'./Land').text
144
+ (response_xml / '/Stations/Station').each do |station|
145
+ code = (station / './Code').text
146
+ name = (station / './Namen/Middel').text
147
+ country = (station / './Land').text
128
148
  result[code] = [name, country]
129
149
  end
130
150
  result
131
151
  end
132
152
 
133
153
  def parse_disruptions(response_xml)
134
- result = {planned: [], unplanned: []}
135
- (response_xml/'/Storingen').each do |disruption|
136
- (disruption/'Ongepland/Storing').each do |unplanned|
137
- unplanned_disruption = UnplannedDisruption.new
138
- unplanned_disruption.id = (unplanned/'./id').text
139
- unplanned_disruption.trip = (unplanned/'./Traject').text
140
- unplanned_disruption.reason = (unplanned/'./Reden').text
141
- unplanned_disruption.message = (unplanned/'./Bericht').text
142
- unplanned_disruption.datetime_string = (unplanned/'./Datum').text
143
- unplanned_disruption.cause = (unplanned/'./Oorzaak').text
144
- result[:unplanned] << unplanned_disruption
154
+ result = { planned: [], unplanned: [] }
155
+ (response_xml / '/Storingen').each do |disruption|
156
+ (disruption / 'Ongepland/Storing').each do |unplanned|
157
+ result[:unplanned] << parse_unplanned_disruption(unplanned)
145
158
  end
146
159
 
147
- (disruption/'Gepland/Storing').each do |planned|
148
- planned_disruption = PlannedDisruption.new
149
- planned_disruption.id = (planned/'./id').text
150
- planned_disruption.trip = (planned/'./Traject').text
151
- planned_disruption.reason = (planned/'./Reden').text
152
- planned_disruption.advice = (planned/'./Advies').text
153
- planned_disruption.message = (planned/'./Bericht').text
154
- planned_disruption.cause = (planned/'./Oorzaak').text
155
- result[:planned] << planned_disruption
160
+ (disruption / 'Gepland/Storing').each do |planned|
161
+ result[:planned] << parse_planned_disruption(planned)
156
162
  end
157
163
  end
158
164
  result
159
165
  end
160
166
 
167
+ def parse_unplanned_disruption(disruption)
168
+ result = UnplannedDisruption.new
169
+ result.id = (disruption / './id').text
170
+ result.trip = (disruption / './Traject').text
171
+ result.reason = (disruption / './Reden').text
172
+ result.message = (disruption / './Bericht').text
173
+ result.datetime_string = (disruption / './Datum').text
174
+ result.cause = (disruption / './Oorzaak').text
175
+ result
176
+ end
177
+
178
+ def parse_planned_disruption(disruption)
179
+ result = PlannedDisruption.new
180
+ result.id = (disruption / './id').text
181
+ result.trip = (disruption / './Traject').text
182
+ result.reason = (disruption / './Reden').text
183
+ result.advice = (disruption / './Advies').text
184
+ result.message = (disruption / './Bericht').text
185
+ result.cause = (disruption / './Oorzaak').text
186
+ result
187
+ end
188
+
161
189
  def raise_error_when_response_is_error(xdoc)
162
- (xdoc/'/error').each do |error|
163
- message = (error/'./message').text
190
+ (xdoc / '/error').each do |error|
191
+ message = (error / './message').text
164
192
  raise InvalidStationNameError, message
165
193
  end
166
194
  end
167
195
 
168
196
  def get_xml(url)
169
- response = @client.get url
170
- @last_received_raw_xml = response.content
197
+ response = RestClient::Request.new(url: url, user: username, password: password, method: :get).execute
198
+ @last_received_raw_xml = response.body
171
199
  @last_received_corrected_xml = remove_unwanted_whitespace(@last_received_raw_xml)
172
200
  begin
173
201
  Nokogiri.XML(@last_received_corrected_xml) do |config|
174
202
  config.options = Nokogiri::XML::ParseOptions::STRICT
175
203
  end
176
204
  rescue Nokogiri::XML::SyntaxError => e
177
- raise UnparseableXMLError.new e
205
+ raise UnparseableXMLError, e
178
206
  end
179
-
180
207
  end
181
208
 
182
- def remove_unwanted_whitespace content
183
- content.gsub /<\s*(\/?)\s*?([a-zA-Z0-9]*)\s*([a-zA-Z0-9]*)\s*>/, '<\1\2\3>'
209
+ def remove_unwanted_whitespace(content)
210
+ content.gsub %r{<\s*(/?)\s*?([a-zA-Z0-9]*)\s*([a-zA-Z0-9]*)\s*>}, '<\1\2\3>'
184
211
  end
185
212
 
186
213
  def disruption_url(query)
187
- return "http://webservices.ns.nl/ns-api-storingen?station=#{query}" if query
188
- "http://webservices.ns.nl/ns-api-storingen?actual=true"
214
+ return "https://webservices.ns.nl/ns-api-storingen?station=#{query}" if query
215
+
216
+ 'https://webservices.ns.nl/ns-api-storingen?actual=true'
189
217
  end
190
218
 
191
219
  class PricesResponse
@@ -197,20 +225,19 @@ class NSClient
197
225
  end
198
226
 
199
227
  def enkele_reis
200
- products["Enkele reis"]
228
+ products['Enkele reis']
201
229
  end
202
230
 
203
231
  def dagretour
204
- products["Retour"]
232
+ products['Retour']
205
233
  end
206
-
207
234
  end
208
235
 
209
236
  class ProductPrice
210
237
  attr_accessor :discount, :train_class, :amount
211
238
  DISCOUNT_MAP ||= {
212
- "20% korting" => "reductie_20",
213
- "40% korting" => "reductie_40"
239
+ '20% korting' => 'reductie_20',
240
+ '40% korting' => 'reductie_40'
214
241
  }.freeze
215
242
 
216
243
  def type
@@ -241,5 +268,4 @@ class NSClient
241
268
 
242
269
  class SameDestinationError < StandardError
243
270
  end
244
-
245
271
  end