ns-api 0.0.2

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.
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