Class: NSClient

Inherits:
Object
  • Object
show all
Defined in:
lib/ns_client.rb

Defined Under Namespace

Classes: InvalidStationNameError, MissingParameter, PlannedDisruption, PricesResponse, ProductPrice, SameDestinationError, Station, UnparseableXMLError, UnplannedDisruption

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(username, password) ⇒ NSClient

Returns a new instance of NSClient.



41
42
43
44
45
46
47
# File 'lib/ns_client.rb', line 41

def initialize(username, password)
  @username = username
  @password = password
  @prices_url = PricesUrl.new('https://webservices.ns.nl/ns-api-prijzen-v3')
  @last_received_raw_xml = ''
  @last_received_corrected_xml = ''
end

Instance Attribute Details

#last_received_corrected_xmlObject

Returns the value of attribute last_received_corrected_xml.



39
40
41
# File 'lib/ns_client.rb', line 39

def last_received_corrected_xml
  @last_received_corrected_xml
end

#last_received_raw_xmlObject

Returns the value of attribute last_received_raw_xml.



39
40
41
# File 'lib/ns_client.rb', line 39

def last_received_raw_xml
  @last_received_raw_xml
end

#passwordObject

Returns the value of attribute password.



39
40
41
# File 'lib/ns_client.rb', line 39

def password
  @password
end

#usernameObject

Returns the value of attribute username.



39
40
41
# File 'lib/ns_client.rb', line 39

def username
  @username
end

Instance Method Details

#disruption_url(query) ⇒ Object



213
214
215
216
217
# File 'lib/ns_client.rb', line 213

def disruption_url(query)
  return "https://webservices.ns.nl/ns-api-storingen?station=#{query}" if query

  'https://webservices.ns.nl/ns-api-storingen?actual=true'
end

#disruptions(query = nil) ⇒ Object



57
58
59
60
61
# File 'lib/ns_client.rb', line 57

def disruptions(query = nil)
  response_xml = get_xml(disruption_url(query))
  raise_error_when_response_is_error(response_xml)
  parse_disruptions(response_xml)
end

#get_xml(url) ⇒ Object



196
197
198
199
200
201
202
203
204
205
206
207
# File 'lib/ns_client.rb', line 196

def get_xml(url)
  response = RestClient::Request.new(url: url, user: username, password: password, method: :get).execute
  @last_received_raw_xml = response.body
  @last_received_corrected_xml = remove_unwanted_whitespace(@last_received_raw_xml)
  begin
    Nokogiri.XML(@last_received_corrected_xml) do |config|
      config.options = Nokogiri::XML::ParseOptions::STRICT
    end
  rescue Nokogiri::XML::SyntaxError => e
    raise UnparseableXMLError, e
  end
end

#parse_disruptions(response_xml) ⇒ Object



153
154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/ns_client.rb', line 153

def parse_disruptions(response_xml)
  result = { planned: [], unplanned: [] }
  (response_xml / '/Storingen').each do |disruption|
    (disruption / 'Ongepland/Storing').each do |unplanned|
      result[:unplanned] << parse_unplanned_disruption(unplanned)
    end

    (disruption / 'Gepland/Storing').each do |planned|
      result[:planned] << parse_planned_disruption(planned)
    end
  end
  result
end

#parse_planned_disruption(disruption) ⇒ Object



178
179
180
181
182
183
184
185
186
187
# File 'lib/ns_client.rb', line 178

def parse_planned_disruption(disruption)
  result = PlannedDisruption.new
  result.id = (disruption / './id').text
  result.trip = (disruption / './Traject').text
  result.reason = (disruption / './Reden').text
  result.advice = (disruption / './Advies').text
  result.message = (disruption / './Bericht').text
  result.cause = (disruption / './Oorzaak').text
  result
end

#parse_prices(response_xml) ⇒ Object



85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/ns_client.rb', line 85

def parse_prices(response_xml)
  prices_response = PricesResponse.new
  (response_xml / '/VervoerderKeuzes/VervoerderKeuze').each do |transporter|
    prices_response.tariff_units = (transporter / './Tariefeenheden').text.to_i

    (transporter / 'ReisType').each do |travel_type|
      prices = parse_travel_type(travel_type)

      name = travel_type.attr('name')
      prices_response.products[name] = prices
    end
  end
  prices_response
end

#parse_station(station) ⇒ Object



124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/ns_client.rb', line 124

def parse_station(station)
  s = Station.new
  s.code = parse_station_field(station, './Code')
  s.type = parse_station_field(station, './Type')
  s.country = parse_station_field(station, './Land')
  s.short_name = parse_station_field(station, './Namen/Kort')
  s.name = parse_station_field(station, './Namen/Middel')
  s.long_name = parse_station_field(station, './Namen/Lang')
  s.lat = parse_station_field(station, './Lat')
  s.long = parse_station_field(station, './Lon')
  s.uiccode = parse_station_field(station, './UICCode')
  s
end

#parse_station_field(station, field) ⇒ Object



138
139
140
# File 'lib/ns_client.rb', line 138

def parse_station_field(station, field)
  (station / field).text
end

#parse_stations(response_xml) ⇒ Object



116
117
118
119
120
121
122
# File 'lib/ns_client.rb', line 116

def parse_stations(response_xml)
  result = []
  (response_xml / '/Stations/Station').each do |station|
    result << parse_station(station)
  end
  result
end

#parse_stations_as_map(response_xml) ⇒ Object



142
143
144
145
146
147
148
149
150
151
# File 'lib/ns_client.rb', line 142

def parse_stations_as_map(response_xml)
  result = {}
  (response_xml / '/Stations/Station').each do |station|
    code = (station / './Code').text
    name = (station / './Namen/Middel').text
    country = (station / './Land').text
    result[code] = [name, country]
  end
  result
end

#parse_travel_type(travel_type) ⇒ Object



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/ns_client.rb', line 100

def parse_travel_type(travel_type)
  prices = []

  (travel_type / 'ReisKlasse').each do |travel_class|
    (travel_class / 'Korting/Kortingsprijs').each do |price_element|
      product_price = ProductPrice.new
      product_price.discount = price_element.attr('name')
      product_price.train_class = travel_class.attr('klasse')
      product_price.amount = price_element.attr('prijs').tr(',', '.').to_f
      prices << product_price
    end
  end

  prices
end

#parse_unplanned_disruption(disruption) ⇒ Object



167
168
169
170
171
172
173
174
175
176
# File 'lib/ns_client.rb', line 167

def parse_unplanned_disruption(disruption)
  result = UnplannedDisruption.new
  result.id = (disruption / './id').text
  result.trip = (disruption / './Traject').text
  result.reason = (disruption / './Reden').text
  result.message = (disruption / './Bericht').text
  result.datetime_string = (disruption / './Datum').text
  result.cause = (disruption / './Oorzaak').text
  result
end

#prices(opts = { from: nil, to: nil, via: nil, date: nil }) ⇒ Object



63
64
65
66
67
68
# File 'lib/ns_client.rb', line 63

def prices(opts = { from: nil, to: nil, via: nil, date: nil })
  validate_prices(opts)
  response_xml = get_xml(@prices_url.url(opts))
  raise_error_when_response_is_error(response_xml)
  parse_prices(response_xml)
end

#raise_error_when_response_is_error(xdoc) ⇒ Object



189
190
191
192
193
194
# File 'lib/ns_client.rb', line 189

def raise_error_when_response_is_error(xdoc)
  (xdoc / '/error').each do |error|
    message = (error / './message').text
    raise InvalidStationNameError, message
  end
end

#remove_unwanted_whitespace(content) ⇒ Object



209
210
211
# File 'lib/ns_client.rb', line 209

def remove_unwanted_whitespace(content)
  content.gsub %r{<\s*(/?)\s*?([a-zA-Z0-9]*)\s*([a-zA-Z0-9]*)\s*>}, '<\1\2\3>'
end

#stationsObject



49
50
51
# File 'lib/ns_client.rb', line 49

def stations
  parse_stations(get_xml('https://webservices.ns.nl/ns-api-stations-v2'))
end

#stations_shortObject



53
54
55
# File 'lib/ns_client.rb', line 53

def stations_short
  parse_stations_as_map(get_xml('https://webservices.ns.nl/ns-api-stations-v2'))
end

#validate_price_parameters(opts) ⇒ Object

Raises:



70
71
72
73
74
# File 'lib/ns_client.rb', line 70

def validate_price_parameters(opts)
  raise MissingParameter, 'from and to station is required' if opts[:from].nil? && opts[:to].nil?
  raise MissingParameter, 'from station is required' unless opts[:from]
  raise MissingParameter, 'to station is required' unless opts[:to]
end

#validate_prices(opts) ⇒ Object



76
77
78
79
80
81
82
83
# File 'lib/ns_client.rb', line 76

def validate_prices(opts)
  validate_price_parameters(opts)

  return unless opts[:from] == opts[:to]

  raise SameDestinationError,
        "from (#{opts[:from]}) and to (#{opts[:to]}) parameters should not be equal"
end