ns-api 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. data/.gitignore +18 -0
  2. data/Gemfile +9 -0
  3. data/Gemfile.lock +40 -0
  4. data/README.md +82 -0
  5. data/Rakefile +1 -0
  6. data/lib/ns.rb +29 -0
  7. data/lib/ns/api/request/base.rb +58 -0
  8. data/lib/ns/api/request/disruption_collection.rb +30 -0
  9. data/lib/ns/api/request/travel_advice.rb +34 -0
  10. data/lib/ns/api/response/disruption_collection.rb +58 -0
  11. data/lib/ns/api/response/parser.rb +22 -0
  12. data/lib/ns/api/response/travel_advice.rb +46 -0
  13. data/lib/ns/configuration.rb +14 -0
  14. data/lib/ns/disruption.rb +26 -0
  15. data/lib/ns/disruption_collection.rb +45 -0
  16. data/lib/ns/model.rb +13 -0
  17. data/lib/ns/station.rb +8 -0
  18. data/lib/ns/travel_option.rb +28 -0
  19. data/lib/ns/trip.rb +80 -0
  20. data/lib/version.rb +3 -0
  21. data/ns.gemspec +24 -0
  22. data/spec/fixtures/ns_disruptions_no_results.xml +10 -0
  23. data/spec/fixtures/ns_disruptions_with_results.xml +23 -0
  24. data/spec/fixtures/ns_travel_advice_response.xml +2444 -0
  25. data/spec/ns/api/request/base_spec.rb +67 -0
  26. data/spec/ns/api/request/disruption_collection_spec.rb +34 -0
  27. data/spec/ns/api/request/travel_advice_spec.rb +53 -0
  28. data/spec/ns/api/response/disruption_collection_spec.rb +43 -0
  29. data/spec/ns/api/response/parser_spec.rb +17 -0
  30. data/spec/ns/api/response/travel_advice_spec.rb +61 -0
  31. data/spec/ns/disruption_collection_spec.rb +32 -0
  32. data/spec/ns/disruption_spec.rb +33 -0
  33. data/spec/ns/station_spec.rb +11 -0
  34. data/spec/ns/travel_option_spec.rb +41 -0
  35. data/spec/ns/trip_spec.rb +85 -0
  36. data/spec/ns_spec.rb +17 -0
  37. data/spec/spec_helper.rb +19 -0
  38. metadata +147 -0
@@ -0,0 +1,67 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ns::Api::Request::Base do
4
+
5
+ class Dummy < Ns::Api::Request::Base; end
6
+ class DummyResponse; end
7
+
8
+ subject { Ns::Api::Request::Base.new }
9
+
10
+ let(:xml) { File.read(File.join($ROOT, 'spec/fixtures/ns_travel_advice_response.xml')) }
11
+ let(:response) { HTTPI::Response.new(200, [], xml) }
12
+
13
+ it 'should disable HTTPI logging' do
14
+ HTTPI.should_receive(:log=).with(false)
15
+ Dummy.new
16
+ end
17
+
18
+ it 'should not implement base_uri' do
19
+ lambda { subject.class.send(:base_uri) }.should raise_error
20
+ end
21
+
22
+ it 'should not implement query' do
23
+ lambda { subject.send(:query) }.should raise_error
24
+ end
25
+
26
+ it 'should not implement response_class' do
27
+ lambda { subject.class.send(:response_class) }.should raise_error
28
+ end
29
+
30
+ it 'should have an http request' do
31
+ HTTPI::Request.should_receive(:new)
32
+ subject.class.stub!(:base_uri).and_return('http://foo.com')
33
+ subject.send(:http_request)
34
+ end
35
+
36
+ it 'should set the query and credentials' do
37
+ request = HTTPI::Request.new('http://foo.com')
38
+
39
+ request.should_receive(:query=).with(an_instance_of(Hash))
40
+ Ns.configuration.should_receive(:username)
41
+ Ns.configuration.should_receive(:password)
42
+
43
+ HTTPI::Request.stub!(:new).and_return(request)
44
+ subject.stub!(:query).and_return({foo: 'bar'})
45
+ subject.class.stub!(:base_uri).and_return('http://foo.com')
46
+
47
+ subject.send(:http_request_with_query_and_authentication)
48
+ end
49
+
50
+ it 'should return the url for the request' do
51
+ request = HTTPI::Request.new('http://foo.com')
52
+ subject.stub!(:http_request).and_return(request)
53
+ subject.stub!(:query).and_return({foo: 'bar'})
54
+
55
+ subject.send(:url_for_request).should be_an_instance_of(HTTPI::Request)
56
+ end
57
+
58
+ it 'should fetch the plain text response body' do
59
+ subject.class.stub!(:base_uri).and_return('http://foo.com')
60
+ subject.stub!(:query).and_return({})
61
+ HTTPI.should_receive(:get).and_return(response)
62
+ response.should_receive(:body)
63
+
64
+ subject.send(:response_body)
65
+ end
66
+
67
+ end
@@ -0,0 +1,34 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ns::Api::Request::DisruptionCollection do
4
+
5
+ let(:disruption_collection) { Ns::DisruptionCollection.new(station: 'asd') }
6
+ subject { Ns::Api::Request::DisruptionCollection.new(disruption_collection: disruption_collection) }
7
+
8
+ it 'has a base_uri' do
9
+ subject.class.base_uri.should == 'http://webservices.ns.nl/ns-api-storingen'
10
+ end
11
+
12
+ it 'has a response_class' do
13
+ subject.class.response_class.should == Ns::Api::Response::DisruptionCollection
14
+ end
15
+
16
+ describe 'query' do
17
+
18
+ let(:query) { subject.send(:query) }
19
+
20
+ it 'should have a station' do
21
+ query[:station].should == disruption_collection.station
22
+ end
23
+
24
+ it 'should have an actual' do
25
+ query[:actual].should == disruption_collection.actual
26
+ end
27
+
28
+ it 'should have an include_planned' do
29
+ query[:unplanned].should == disruption_collection.include_planned
30
+ end
31
+
32
+ end
33
+
34
+ end
@@ -0,0 +1,53 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ns::Api::Request::TravelAdvice do
4
+
5
+ let(:trip) { Ns::Trip.new(from: 'edc', to: 'asd', departure: Time.now) }
6
+ let(:xml) { File.read(File.join($ROOT, 'spec/fixtures/ns_travel_advice_response.xml')) }
7
+ let(:response) { HTTPI::Response.new(200, [], xml) }
8
+ subject { Ns::Api::Request::TravelAdvice.new(trip: trip) }
9
+
10
+ it 'has a base uri' do
11
+ subject.class.base_uri.should == 'http://webservices.ns.nl/ns-api-treinplanner'
12
+ end
13
+
14
+ it 'has a trip' do
15
+ subject.trip.should == trip
16
+ end
17
+
18
+ it 'forwards the response to the correct response class' do
19
+ subject.stub!(:response_body).and_return(xml)
20
+ subject.response
21
+ end
22
+
23
+ describe 'query' do
24
+
25
+ let(:query) { subject.send(:query) }
26
+
27
+ it 'should have a fromStation' do
28
+ query[:fromStation].should == trip.from.name
29
+ end
30
+
31
+ it 'should have a toStation' do
32
+ query[:toStation].should == trip.to.name
33
+ end
34
+
35
+ it 'should have a dateTime' do
36
+ query[:dateTime].should == trip.formatted_time
37
+ end
38
+
39
+ it 'should have a departure' do
40
+ query[:departure].should == trip.departure?
41
+ end
42
+
43
+ it 'should have a hslAllowed' do
44
+ query[:hslAllowed].should == trip.allow_hsl
45
+ end
46
+
47
+ it 'should have a yearCard' do
48
+ query[:yearCard].should == trip.year_card
49
+ end
50
+
51
+ end
52
+
53
+ end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ns::Api::Response::DisruptionCollection do
4
+
5
+ let(:parsed_response) { double(:parsed_response) }
6
+ let(:disruption_collection) { double(:disruption_collection) }
7
+ let(:raw_disruption) { double(:raw_disruption) }
8
+ let(:planned_disruptions) { [ [ 'Storing', raw_disruption ] ] }
9
+ let(:unplanned_disruptions) { [ [ 'Storing', raw_disruption ] ] }
10
+ subject { Ns::Api::Response::DisruptionCollection.new(parsed_response: parsed_response) }
11
+
12
+ before do
13
+ parsed_response.stub!(:[]).with('Storingen').and_return(disruption_collection)
14
+ disruption_collection.stub!(:[]).with('Gepland').and_return(planned_disruptions)
15
+ disruption_collection.stub!(:[]).with('Ongepland').and_return(unplanned_disruptions)
16
+ end
17
+
18
+ it 'should not error if parsed response is empty' do
19
+ empty = Ns::Api::Response::DisruptionCollection.new(parsed_response: {})
20
+
21
+ empty.planned_disruptions.should == []
22
+ empty.unplanned_disruptions.should == []
23
+ end
24
+
25
+ it 'should fetch planned disruptions' do
26
+ parsed_response.should_receive(:has_key?).with('Storingen').and_return(true)
27
+ disruption_collection.should_receive(:has_key?).and_return(true)
28
+ raw_disruption.should_receive(:[]).any_number_of_times.and_return('')
29
+ Ns::Disruption.should_receive(:new)
30
+
31
+ subject.planned_disruptions
32
+ end
33
+
34
+ it 'should fetch unplanned disruptions' do
35
+ parsed_response.should_receive(:has_key?).with('Storingen').and_return(true)
36
+ disruption_collection.should_receive(:has_key?).and_return(true)
37
+ raw_disruption.should_receive(:[]).any_number_of_times.and_return('')
38
+ Ns::Disruption.should_receive(:new)
39
+
40
+ subject.unplanned_disruptions
41
+ end
42
+
43
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ns::Api::Response::Parser do
4
+
5
+ let(:xml) { File.read(File.join($ROOT, 'spec/fixtures/ns_travel_advice_response.xml')) }
6
+ subject { Ns::Api::Response::Parser.new(response_text: xml) }
7
+
8
+ it 'should have a parser' do
9
+ Nori.should_receive(:new)
10
+ subject.send(:parser)
11
+ end
12
+
13
+ it 'should parse a response' do
14
+ subject.parsed_response.class.should == Hash
15
+ end
16
+
17
+ end
@@ -0,0 +1,61 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ns::Api::Response::TravelAdvice do
4
+
5
+ let(:parsed_response) { double(:parsed_response) }
6
+ let(:travel_options) { double(:travel_options) }
7
+ let(:travel_option) { double(:travel_option) }
8
+ subject { Ns::Api::Response::TravelAdvice.new(parsed_response: parsed_response) }
9
+
10
+ before do
11
+ parsed_response.stub!(:[]).and_return(travel_options)
12
+ travel_options.stub!(:[]).and_return(travel_option)
13
+ end
14
+
15
+ it 'should initialize with a parsed response' do
16
+ subject.parsed_response.should == parsed_response
17
+ end
18
+
19
+ it 'should check for the presence of keys' do
20
+ parsed_response.should_receive(:has_key?).with('ReisMogelijkheden').and_return(true)
21
+ parsed_response['ReisMogelijkheden'].should_receive(:has_key?).with('ReisMogelijkheid').and_return(true)
22
+
23
+ subject.send(:raw_travel_options)
24
+ end
25
+
26
+ it 'should map travel options to Ns::TravelOption objects' do
27
+ subject.stub!(:raw_travel_options).and_return([travel_option])
28
+ Ns::TravelOption.should_receive(:new)
29
+
30
+ travel_option.should_receive(:[]).with('GeplandeVertrekTijd')
31
+ travel_option.should_receive(:[]).with('ActueleVertrekTijd')
32
+ travel_option.should_receive(:[]).with('GeplandeAankomstTijd')
33
+ travel_option.should_receive(:[]).with('ActueleAankomstTijd')
34
+ travel_option.should_receive(:[]).with('AantalOverstappen')
35
+ travel_option.should_receive(:[]).with('Optimaal')
36
+ travel_option.should_receive(:[]).with('ReisDeel').and_return([{'ReisStop' => [{ 'Spoor' => '9a' }]}])
37
+
38
+ subject.travel_options
39
+ end
40
+
41
+ it 'should map travel options to Ns::TravelOption objects if only one travel option is present' do
42
+ subject.stub!(:raw_travel_options).and_return([travel_option])
43
+ Ns::TravelOption.should_receive(:new)
44
+
45
+ travel_option.should_receive(:[]).with('GeplandeVertrekTijd')
46
+ travel_option.should_receive(:[]).with('ActueleVertrekTijd')
47
+ travel_option.should_receive(:[]).with('GeplandeAankomstTijd')
48
+ travel_option.should_receive(:[]).with('ActueleAankomstTijd')
49
+ travel_option.should_receive(:[]).with('AantalOverstappen')
50
+ travel_option.should_receive(:[]).with('Optimaal')
51
+ travel_option.should_receive(:[]).with('ReisDeel').and_return({'ReisStop' => [{ 'Spoor' => '9a' }]})
52
+
53
+ subject.travel_options
54
+ end
55
+
56
+ it 'should not error if parsed response is empty' do
57
+ empty = Ns::Api::Response::TravelAdvice.new(parsed_response: {})
58
+ empty.travel_options.should == []
59
+ end
60
+
61
+ end
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ns::DisruptionCollection do
4
+
5
+ subject { Ns::DisruptionCollection.new(station: 'asd') }
6
+
7
+ let(:xml_with_disruptions) { File.read(File.join($ROOT, 'spec/fixtures/ns_disruptions_with_results.xml')) }
8
+ let(:xml_no_disruptions) { File.read(File.join($ROOT, 'spec/fixtures/ns_disruptions_no_results.xml')) }
9
+ let(:response) { double('response') }
10
+ let(:disruption_collection) { double('disruption_collection') }
11
+
12
+ before do
13
+ response.stub!(:planned_disruptions)
14
+ response.stub!(:unplanned_disruptions)
15
+ disruption_collection.stub!(:response).and_return(response)
16
+ subject.stub!(:disruption_collection).and_return(disruption_collection)
17
+ end
18
+
19
+ it 'should fetch a list of planned disruptions around a station' do
20
+ subject.planned_disruptions
21
+ end
22
+
23
+ it 'should fetch a list of unplanned disruptions around a station' do
24
+ subject.unplanned_disruptions
25
+ end
26
+
27
+ it 'has a disruption_collection' do
28
+ object = Ns::DisruptionCollection.new(station: 'asd')
29
+ lambda { object.send(:disruption_collection) }.should_not raise_error
30
+ end
31
+
32
+ end
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ns::Disruption do
4
+
5
+ let(:route) { 'Amsterdam Centraal - Ede Centrum' }
6
+ let(:reason) { ' Op last van de politie' }
7
+ let(:message) { 'Bericht met spaties ' }
8
+ let(:advice) { 'Maak gebruik van overige treinen of bussen' }
9
+ let(:period) { 'Zaterdag 18 en zondag 19 december' }
10
+
11
+ subject {
12
+ Ns::Disruption.new(
13
+ route: route,
14
+ reason: reason,
15
+ message: message,
16
+ advice: advice,
17
+ period: period
18
+ )
19
+ }
20
+
21
+ it 'initializes properly' do
22
+ %w(route period).each do |var|
23
+ subject.send(var).should == send(var)
24
+ end
25
+ end
26
+
27
+ it 'strips and cleans strings of excess spaces' do
28
+ subject.reason.should == 'Op last van de politie'
29
+ subject.message.should == 'Bericht met spaties'
30
+ subject.advice.should == 'Maak gebruik van overige treinen of bussen'
31
+ end
32
+
33
+ end
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ns::Station do
4
+
5
+ subject { Ns::Station.new(name: 'edc') }
6
+
7
+ it 'should have a name' do
8
+ subject.name.should == 'edc'
9
+ end
10
+
11
+ end
@@ -0,0 +1,41 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ns::TravelOption do
4
+
5
+ let(:planned_departure) { DateTime.now }
6
+ let(:actual_departure) { DateTime.now + (80.0 / 60 / 60 / 24) }
7
+ let(:planned_arrival) { planned_departure + (3600.0 / 60 / 60 / 24) }
8
+ let(:actual_arrival) { actual_departure + (3600.0 / 60 / 60 / 24) }
9
+ let(:changes) { 2 }
10
+ let(:platform) { '9a' }
11
+
12
+ subject {
13
+ Ns::TravelOption.new(
14
+ planned_departure: planned_departure,
15
+ actual_departure: actual_departure,
16
+ planned_arrival: planned_arrival,
17
+ actual_arrival: actual_arrival,
18
+ changes: changes,
19
+ platform: platform
20
+ )
21
+ }
22
+
23
+ it 'should initialize properly' do
24
+ %w(planned_departure actual_departure planned_arrival actual_arrival changes platform).each do |var|
25
+ subject.send(var).should == send(var)
26
+ end
27
+ end
28
+
29
+ it 'should calculate the planned duration' do
30
+ subject.planned_duration.should == 3600
31
+ end
32
+
33
+ it 'should calculate the actual duration' do
34
+ subject.actual_duration.should == 3600
35
+ end
36
+
37
+ it 'should calculate the delay' do
38
+ subject.delay.should == 80
39
+ end
40
+
41
+ end
@@ -0,0 +1,85 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ns::Trip do
4
+
5
+ subject { Ns::Trip.new(from: 'edc', to: 'asd', departure: (Time.now + 3600)) }
6
+
7
+ let(:time1) { Time.now + 3600 }
8
+ let(:time2) { Time.now + 8600 }
9
+ let(:xml) { File.read(File.join($ROOT, 'spec/fixtures/ns_travel_advice_response.xml')) }
10
+ let(:departure_trip) { Ns::Trip.new(from: 'edc', to: 'asd', departure: time1) }
11
+ let(:arrival_trip) { Ns::Trip.new(from: 'edc', to: 'asd', arrival: time2) }
12
+ let(:trip_without_time) { Ns::Trip.new(from: 'edc', to: 'asd') }
13
+
14
+ it 'should map origin and destination to station classes' do
15
+ subject.from.class.should == Ns::Station
16
+ subject.to.class.should == Ns::Station
17
+ end
18
+
19
+ it 'has a time' do
20
+ departure_trip.time.should == time1
21
+ arrival_trip.time.should == time2
22
+ end
23
+
24
+ it 'has a default time' do
25
+ Time.should_receive(:now)
26
+ trip_without_time.time
27
+ end
28
+
29
+ it 'defaults to arrival if no time given' do
30
+ trip_without_time.departure?.should == false
31
+ end
32
+
33
+ it 'has a formatted time' do
34
+ departure_trip.formatted_time.should == time1.iso8601
35
+ arrival_trip.formatted_time.should == time2.iso8601
36
+ end
37
+
38
+ it 'tells wether it is a departure or arrival time' do
39
+ departure_trip.departure?.should == true
40
+ arrival_trip.departure?.should == false
41
+ end
42
+
43
+ it 'has travel options' do
44
+ response = double('travel_advice_response')
45
+ response.stub!(:travel_options)
46
+ travel_advice = double('travel_advice')
47
+ travel_advice.stub!(:response).and_return(response)
48
+ Ns::Api::Request::TravelAdvice.stub!(:new).and_return(travel_advice)
49
+
50
+ travel_options = subject.travel_options
51
+ end
52
+
53
+ it 'has a default allow_hsl' do
54
+ subject.allow_hsl.should == false
55
+ end
56
+
57
+ it 'has a default year_card' do
58
+ subject.year_card.should == false
59
+ end
60
+
61
+ describe 'validations' do
62
+
63
+ let(:trip1) { Ns::Trip.new(from: 'edc', to: 'asd') }
64
+ let(:trip2) { Ns::Trip.new(from: 'edc', to: 'asd', departure: '') }
65
+ let(:trip3) { Ns::Trip.new(from: 'edc', to: 'asd', arrival: '') }
66
+ let(:trip4) { Ns::Trip.new(from: 'edc', to: 'asd', departure: Time.now) }
67
+ let(:trip5) { Ns::Trip.new(from: 'edc', to: 'asd', arrival: Time.now) }
68
+ let(:trip6) { Ns::Trip.new(from: 'edc', to: 'asd', arrival: Date.today) }
69
+ let(:trip7) { Ns::Trip.new(arrival: Date.today) }
70
+ let(:trip8) { Ns::Trip.new(from: 'edc', arrival: Date.today) }
71
+
72
+ it 'should validate departure/arrival times' do
73
+ trip1.valid?.should == false
74
+ trip2.valid?.should == false
75
+ trip3.valid?.should == false
76
+ trip4.valid?.should == true
77
+ trip5.valid?.should == true
78
+ trip6.valid?.should == false
79
+ trip7.valid?.should == false
80
+ trip8.valid?.should == false
81
+ end
82
+
83
+ end
84
+
85
+ end