rail_feeds 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +8 -1
  3. data/.travis.yml +17 -4
  4. data/CHANGELOG.md +12 -0
  5. data/README.md +11 -7
  6. data/doc/guides/National Rail/Knowledge Base/National Service Indicator.md +21 -0
  7. data/doc/guides/Network Rail/CORPUS.md +7 -3
  8. data/doc/guides/Network Rail/SMART.md +6 -2
  9. data/doc/guides/Network Rail/Schedule.md +4 -4
  10. data/lib/rail_feeds/credentials.rb +30 -0
  11. data/lib/rail_feeds/http_client.rb +56 -0
  12. data/lib/rail_feeds/logging.rb +0 -2
  13. data/lib/rail_feeds/national_rail/credentials.rb +11 -0
  14. data/lib/rail_feeds/national_rail/http_client.rb +45 -0
  15. data/lib/rail_feeds/national_rail/knowledge_base/national_service_indicator.rb +100 -0
  16. data/lib/rail_feeds/national_rail/knowledge_base.rb +8 -0
  17. data/lib/rail_feeds/national_rail.rb +9 -0
  18. data/lib/rail_feeds/network_rail/corpus.rb +5 -6
  19. data/lib/rail_feeds/network_rail/credentials.rb +0 -11
  20. data/lib/rail_feeds/network_rail/http_client.rb +8 -44
  21. data/lib/rail_feeds/network_rail/schedule/association.rb +2 -2
  22. data/lib/rail_feeds/network_rail/schedule/data.rb +3 -2
  23. data/lib/rail_feeds/network_rail/schedule/days.rb +1 -0
  24. data/lib/rail_feeds/network_rail/schedule/fetcher.rb +1 -2
  25. data/lib/rail_feeds/network_rail/schedule/header/json.rb +2 -2
  26. data/lib/rail_feeds/network_rail/schedule/header.rb +0 -3
  27. data/lib/rail_feeds/network_rail/schedule/parser/json.rb +0 -2
  28. data/lib/rail_feeds/network_rail/schedule/parser.rb +1 -4
  29. data/lib/rail_feeds/network_rail/schedule/tiploc.rb +2 -2
  30. data/lib/rail_feeds/network_rail/schedule/train_schedule/location.rb +1 -4
  31. data/lib/rail_feeds/network_rail/schedule/train_schedule.rb +8 -12
  32. data/lib/rail_feeds/network_rail/schedule.rb +3 -10
  33. data/lib/rail_feeds/network_rail/smart.rb +17 -17
  34. data/lib/rail_feeds/network_rail/stomp_client.rb +2 -3
  35. data/lib/rail_feeds/network_rail.rb +0 -7
  36. data/lib/rail_feeds/version.rb +1 -1
  37. data/lib/rail_feeds.rb +40 -4
  38. data/rail_feeds.gemspec +28 -23
  39. data/spec/rail_feeds/credentials_spec.rb +28 -1
  40. data/spec/rail_feeds/http_client_spec.rb +75 -0
  41. data/spec/rail_feeds/national_rail/credentials_spec.rb +13 -0
  42. data/spec/rail_feeds/national_rail/http_client_spec.rb +57 -0
  43. data/spec/rail_feeds/national_rail/knowledge_base/national_service_indicator_spec.rb +122 -0
  44. data/spec/rail_feeds/national_rail/knowledge_base_spec.rb +4 -0
  45. data/spec/rail_feeds/national_rail_spec.rb +7 -0
  46. data/spec/rail_feeds/network_rail/corpus_spec.rb +2 -2
  47. data/spec/rail_feeds/network_rail/credentials_spec.rb +3 -12
  48. data/spec/rail_feeds/network_rail/http_client_spec.rb +7 -75
  49. data/spec/rail_feeds/network_rail/schedule/data_spec.rb +1 -1
  50. data/spec/rail_feeds/network_rail/smart_spec.rb +2 -2
  51. data/spec/rail_feeds/network_rail/stomp_client_spec.rb +1 -1
  52. metadata +48 -9
  53. data/file +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bd597c45ef2dc68d4da4278cfeda76ad9ae61e128309071a89c85adb27b510e4
4
- data.tar.gz: 4af4ee4fb4302f304b444e87804ab6d3813098ccf637fe957b57ac9cbbbeb8f3
3
+ metadata.gz: 48c8d73c18dddf2cbe0cdc89764f686112157e85b910ac07140a0718871aa20b
4
+ data.tar.gz: e27ab1045735dc9e1c69419821af37610c6234ca9ceda8fb7664614e3abdbafd
5
5
  SHA512:
6
- metadata.gz: 23f62dfd13351944c0c24e204e5c9788a53a4871d03440a5dfae3a121769044c198bc41b7330b3f54a83bb82a4488218b4958b2575797d9d0a637729fef32268
7
- data.tar.gz: b3e18f1f140f3e16c6c2ad67358cd2269dc4ed43a450384347fed1c73d208353cd13029f2b1c330725f87880be7494e894d2f451baf30a39c806aef9199501a7
6
+ metadata.gz: 58fb1b17bd665d1d1881d143bccbc5f1ee1a743710b28ecd8f88867b52ee4e238bcc438072425bf3098e3142769a9e671aea74796629c5015b82a0bb35c95770
7
+ data.tar.gz: 0ea4810aa3c8d91de9e7e0a6fad6adf26a7c4c7fbdb35c6a41e9bd47ad365b91be3e9de3ac7ac50baa416edadfa9231703bf25ba66a9085f5c359274fd7d3b7c
data/.rubocop.yml CHANGED
@@ -1,5 +1,9 @@
1
+ require:
2
+ - rubocop-performance
1
3
  AllCops:
2
- TargetRubyVersion: 2.3
4
+ TargetRubyVersion: 2.4
5
+ Exclude:
6
+ - '*.gemspec'
3
7
  Style/SignalException:
4
8
  Enabled: false
5
9
  Metrics/MethodLength:
@@ -14,6 +18,9 @@ Metrics/LineLength:
14
18
  Layout/TrailingBlankLines:
15
19
  Exclude:
16
20
  - rail_feeds.gemspec
21
+ Style/BracesAroundHashParameters:
22
+ Exclude:
23
+ - spec/**/*
17
24
  Style/WordArray:
18
25
  Exclude:
19
26
  - spec/**/*
data/.travis.yml CHANGED
@@ -1,11 +1,24 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.4.0
4
- - 2.4.1
5
- - 2.4.2
6
- - 2.4.3
3
+ - 2.4.4
4
+ - 2.4.5
5
+ - 2.4.6
7
6
  - 2.5.0
8
7
  - 2.5.1
8
+ - 2.5.2
9
+ - 2.5.3
10
+ - 2.5.4
11
+ - 2.5.5
12
+ - 2.6.0
13
+ - 2.6.1
14
+ - 2.6.2
15
+ - jruby-9.2.0.0
16
+ - jruby-9.2.1.0
17
+ - jruby-9.2.3.0
18
+ - jruby-9.2.4.0
19
+ - jruby-9.2.4.1
20
+ - jruby-9.2.5.0
21
+ - jruby-9.2.6.0
9
22
  gemfile:
10
23
  - Gemfile
11
24
  branches:
data/CHANGELOG.md CHANGED
@@ -1,3 +1,15 @@
1
+ ## Version 0.0.2
2
+
3
+ * Add support for:
4
+ * rubies 2.4.4 - 2.6.2
5
+ * jrubyies 9.2.0.0 - 9.2.6.0
6
+ * Sort API consistency - when passing credentials use positional not keywork arguments, except:
7
+ * Initializing a new HTTP or Stomp client
8
+ * Initializing a new NetworkRail Schedule Fetcher
9
+ * Add National rail - Knowledge base - National service indicator via HTTP.
10
+ * Fix issue 1: OpenURI returns a StringIO not TempFile when size is under 10KB.
11
+ * Fix "undefined method `parse_cif_file'" when loading Network Rail schedule data.
12
+
1
13
  ## Version 0.0.1
2
14
 
3
15
  * Initial release.
data/README.md CHANGED
@@ -19,8 +19,12 @@ and Staging (which is what is currently being developed ready for moving to mast
19
19
  ## Ruby Versions
20
20
  This gem supports the following versions of ruby, it may work on other versions but is not tested against them so don't rely on it.
21
21
 
22
- * 2.4.0 - 2.4.3
23
- * 2.5.0 - 2.5.1
22
+ * ruby:
23
+ * 2.4.4 - 2.4.6
24
+ * 2.5.0 - 2.5.5
25
+ * 2.6.0 - 2.6.2
26
+ * jruby:
27
+ * 9.2.0.0 - 9.2.6.0
24
28
 
25
29
 
26
30
  ## Rail Feeds
@@ -50,10 +54,10 @@ We follow the [Semantic Versioning](http://semver.org/) concept.
50
54
 
51
55
  ### Sources
52
56
 
53
- | Source | Module | Module Alias | Support |
54
- | ------------- | ----------------------- | ------------ | -------------------------- |
55
- | Network Rail | RailFeeds::NetworkRail | NetRailFeeds | Being developed |
56
- | National Rail | RailFeeds::NationalRail | NatRailFeeds | None yet - any volunteers? |
57
+ | Source | Module | Module Alias | Support |
58
+ | ------------- | ----------------------- | ------------ | --------------- |
59
+ | Network Rail | RailFeeds::NetworkRail | NetRailFeeds | Being developed |
60
+ | National Rail | RailFeeds::NationalRail | NatRailFeeds | |
57
61
 
58
62
  ### Feeds
59
63
 
@@ -72,6 +76,6 @@ We follow the [Semantic Versioning](http://semver.org/) concept.
72
76
  | National Rail | stomp | Darwin Push Port | |
73
77
  | National Rail | stomp | Darwin Timetable Feed | |
74
78
  | National Rail | stomp | Knowledgebase | |
75
- | National Rail | http | Knowledgebase | |
79
+ | National Rail | http | Knowledgebase | Can download, fetch and parse NSI. |
76
80
  | National Rail | soap | Darwin Webservice | |
77
81
  | National Rail | rest | Historical Service Performance | |
@@ -0,0 +1,21 @@
1
+ # National Rail - National Service Indicator
2
+
3
+ The national service indicator provides information on the current service
4
+ provided by each TOC.
5
+
6
+ ```ruby
7
+ # Download the file and then get the data from it
8
+ RailFeeds::NationalRail::Credentials.configure(
9
+ username: 'YOUR USERNAME HERE',
10
+ password: 'YOUR PASSWORD HERE'
11
+ )
12
+ RailFeeds::NationalRail::KnowledgeBase::NationalServiceIndicator.download('file name')
13
+ data = RailFeeds::NationalRail::KnowledgeBase::NationalServiceIndicator.load_file('file name')
14
+
15
+ # Get data by fetching it from the web
16
+ RailFeeds::NationalRail::Credentials.configure(
17
+ username: 'YOUR USERNAME HERE',
18
+ password: 'YOUR PASSWORD HERE'
19
+ )
20
+ data = RailFeeds::NationalRail::KnowledgeBase::NationalServiceIndicator.fetch_data
21
+ ```
@@ -1,4 +1,4 @@
1
- # Network Rail CORPUS (Codes for Operations, Retail & Planning – a Unified Solution)
1
+ # Network Rail - CORPUS (Codes for Operations, Retail & Planning – a Unified Solution)
2
2
 
3
3
  The CORPUS data is a list of indentification information for locations around the network.
4
4
  See <https://wiki.openraildata.com/index.php/Reference_Data#CORPUS:_Location_Reference_Data>
@@ -16,13 +16,17 @@ You'll get an array of a data struct with the following attributes:
16
16
 
17
17
  ```ruby
18
18
  # Download the CORPUS data and get the data from it
19
+ RailFeeds::NetworkRail::Credentials.configure(
20
+ username: 'YOUR USERNAME HERE',
21
+ password: 'YOUR PASSWORD HERE'
22
+ )
19
23
  temp_file = RailFeeds::NetworkRail::CORPUS.fetch
20
- data = RailFeeds::NetworkRail::CORPUS.load_file(temp_file.path)
24
+ data = RailFeeds::NetworkRail::CORPUS.load_file(temp_file)
21
25
 
22
26
  # Get data from a previously saved file
23
27
  data = RailFeeds::NetworkRail::CORPUS.load_file('PATH TO FILE.json.gz')
24
28
 
25
- # Get data from a previously saved and extracted file
29
+ # Get data from a previously saved and unzipped file
26
30
  data = RailFeeds::NetworkRail::CORPUS.load_file('PATH TO FILE.json')
27
31
 
28
32
  # Get data by fetching it from the web
@@ -1,4 +1,4 @@
1
- # Network Rail SMART
1
+ # Network Rail - SMART
2
2
 
3
3
  The SMART data is a periodically updated list of mappings between train describer berths
4
4
  and locations, allowing for TD events to be translated into arrival/departure from location
@@ -18,8 +18,12 @@ reachable in each direction.
18
18
 
19
19
  ```ruby
20
20
  # Download the SMART data and get the data from it
21
+ RailFeeds::NetworkRail::Credentials.configure(
22
+ username: 'YOUR USERNAME HERE',
23
+ password: 'YOUR PASSWORD HERE'
24
+ )
21
25
  temp_file = RailFeeds::NetworkRail::SMART.fetch
22
- step_data = RailFeeds::NetworkRail::SMART.load_file(temp_file.path)
26
+ step_data = RailFeeds::NetworkRail::SMART.load_file(temp_file)
23
27
 
24
28
  # Get the SMART data from a previously saved file
25
29
  step_data = RailFeeds::NetworkRail::SMART.load_file('PATH TO FILE.json.gz')
@@ -1,4 +1,4 @@
1
- # Network Rail Schedule
1
+ # Network Rail - Schedule
2
2
 
3
3
  The schedule files from Network Rail contain:
4
4
 
@@ -36,14 +36,14 @@ RailFeeds::NetworkRail::Credentials.configure(
36
36
  # 2. Fetch some files
37
37
  fetcher = RailFeeds::NetworkRail::Schedule::Fetcher.new
38
38
 
39
- fetcher.fetch_all_full(:cif) do |full_file|
39
+ fetcher.fetch_all_full(:cif) do |full_file_as_an_io|
40
40
  ...
41
41
  end
42
42
 
43
- fetcher.fetch_all_update('fri', :cif) do |update_file|
43
+ fetcher.fetch_all_update('fri', :cif) do |update_file_as_an_io|
44
44
  ...
45
45
  end
46
- # Each of the file variables will contain a TempFile which can be used to read
46
+ # Each of the file variables will contain an IO object which can be used to read
47
47
  # the CIF data (or passed to the parser to make use of). The files will be deleted
48
48
  # at the end of the block.
49
49
  ```
@@ -34,6 +34,36 @@ module RailFeeds
34
34
  @password = password.to_s.clone
35
35
  end
36
36
 
37
+ # Get an array of [username, password].
38
+ # @return [Array<String>]
39
+ def to_a
40
+ [username, password]
41
+ end
42
+
43
+ # Get a hash of { username: ?, password: ? }.
44
+ # @return [Hash<Symbol => String>]
45
+ def to_h
46
+ {
47
+ username: username,
48
+ password: password
49
+ }
50
+ end
51
+
52
+ # Get an array of [username, password].
53
+ # @return [Array<String>]
54
+ def self.to_a
55
+ [username, password]
56
+ end
57
+
58
+ # Get a hash of { username: ?, password: ? }.
59
+ # @return [Hash<Symbol => String>]
60
+ def self.to_h
61
+ {
62
+ username: username,
63
+ password: password
64
+ }
65
+ end
66
+
37
67
  def self.username
38
68
  @username.clone
39
69
  end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailFeeds
4
+ # A wrapper class for ::Net::HTTP
5
+ class HTTPClient
6
+ include Logging
7
+
8
+ # Initialize a new http client.
9
+ # @param [RailFeeds::Credentials] credentials
10
+ # The credentials for connecting to the feed.
11
+ # @param [Logger] logger
12
+ # The logger for outputting evetns, if nil the global logger will be used.
13
+ def initialize(credentials: nil, logger: nil)
14
+ @credentials = credentials
15
+ self.logger = logger unless logger.nil?
16
+ end
17
+
18
+ # Fetch path from server.
19
+ # @param [String] url The URL to fetch.
20
+ # @yield contents
21
+ # @yieldparam [IO] file Either a Tempfile or StringIO.
22
+ def fetch(url, options = {})
23
+ logger.debug "fetching #{url.inspect}"
24
+ options[:http_basic_authentication] = @credentials.to_a
25
+ yield URI(url).open(options)
26
+ end
27
+
28
+ # Fetch path from server and unzip it.
29
+ # @param [String] url The URL to fetch. For child classes this is just the path.
30
+ # @yield contents
31
+ # @yieldparam [Zlib::GzipReader] reader The unzippable content of the file.
32
+ def fetch_unzipped(url)
33
+ logger.debug "get_unzipped(#{url.inspect})"
34
+ fetch(url) do |gz_file|
35
+ reader = Zlib::GzipReader.new gz_file
36
+ yield reader
37
+ end
38
+ end
39
+
40
+ # Download path from server.
41
+ # @param [String] url The URL to download. For child classes this is just the path.
42
+ # @param [String] file The path to the file to save the contents in.
43
+ def download(url, file)
44
+ logger.debug "download(#{url.inspect}, #{file.inspect})"
45
+ fetch(url) do |src|
46
+ File.open(file, 'w') do |dst|
47
+ IO.copy_stream src, dst
48
+ end
49
+ end
50
+ end
51
+
52
+ private
53
+
54
+ attr_reader :credentials
55
+ end
56
+ end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'logger'
4
-
5
3
  module RailFeeds
6
4
  # A Module to provide a global logger
7
5
  module Logging
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailFeeds
4
+ module NationalRail
5
+ # A Class to store username & password required to access national rail feeds
6
+ # Can be used to set a global default but create new instances with
7
+ # specific ones for a specific use.
8
+ class Credentials < RailFeeds::Credentials
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailFeeds
4
+ module NationalRail
5
+ # A wrapper class for ::Net::HTTP
6
+ class HTTPClient < RailFeeds::HTTPClient
7
+ def initialize(credentials: nil, **args)
8
+ credentials ||= RailFeeds::NationalRail::Credentials
9
+ super
10
+ end
11
+
12
+ # Fetch path from server.
13
+ # @param [String] path The path to fetch.
14
+ # @yield contents
15
+ # @yieldparam [IO] file Either a Tempfile or StringIO.
16
+ def fetch(path)
17
+ super "https://datafeeds.nationalrail.co.uk/#{path}", 'X-Auth-Token' => auth_token
18
+ end
19
+
20
+ private
21
+
22
+ # rubocop:disable Metrics/AbcSize
23
+ def auth_token
24
+ return @auth_token if !@auth_token.nil? && @auth_token_expires_at >= Time.now
25
+
26
+ logger.info 'Getting an auth token for national rail.'
27
+ response = Net::HTTP.post_form(
28
+ URI('https://datafeeds.nationalrail.co.uk/authenticate'),
29
+ credentials.to_h
30
+ )
31
+ response.value # Raise an exception if not successful
32
+ data = JSON.parse(response.body)
33
+ logger.debug "Got auth token data: #{data.inspect}"
34
+ token = data.fetch('token')
35
+
36
+ # Token expires in 1 hour. Using 55 minutes provides a safety margin.
37
+ @auth_token_expires_at = Time.now + (55 * 60)
38
+ logger.debug "Auth token expires at #{@auth_token_expires_at}."
39
+
40
+ @auth_token = token
41
+ end
42
+ # rubocop:enable Metrics/AbcSize
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailFeeds
4
+ module NationalRail
5
+ module KnowledgeBase
6
+ # A module for accessing the national service indicator
7
+ # from the national rail knowledge base.
8
+ module NationalServiceIndicator
9
+ TOC = Struct.new(
10
+ :code, :name, :status, :twitter_account, :additional_info, :service_groups
11
+ ) do
12
+ def to_s
13
+ "#{code} - #{name}\n" \
14
+ "#{status}\n#{service_groups.join("\n")}\n" \
15
+ "@#{twitter_account} - #{additional_info}"
16
+ end
17
+ end
18
+
19
+ Status = Struct.new(:title, :description, :image) do
20
+ def to_s
21
+ "#{title} - #{description} - #{image}"
22
+ end
23
+ end
24
+
25
+ ServiceGroup = Struct.new(:disruption_id, :name, :detail, :url) do
26
+ def to_s
27
+ "#{name} - #{detail}\n#{disruption_id} #{url}"
28
+ end
29
+ end
30
+
31
+ # Download the current data.
32
+ # @param [RailFeeds::NationalRail::Credentials] credentials
33
+ # @param [String] file
34
+ # The path to the file to save the .xml download in.
35
+ def self.download(file, credentials = Credentials)
36
+ client = HTTPClient.new(credentials: credentials)
37
+ client.download 'darwin/api/staticfeeds/4.0/serviceIndicators', file
38
+ end
39
+
40
+ # Fetch the current data.
41
+ # @param [RailFeeds::NationalRail::Credentials] credentials
42
+ # @return [IO]
43
+ def self.fetch(credentials = Credentials, &block)
44
+ client = HTTPClient.new(credentials: credentials)
45
+ client.fetch 'darwin/api/staticfeeds/4.0/serviceIndicators', &block
46
+ end
47
+
48
+ # Load data from either a .json or .json.gz file.
49
+ # @param [String] file The path of the file to open.
50
+ # @return
51
+ # [Array<RailFeeds::NationalRail::KnowledgeBase::NationalServiceIndicator::TOC>]
52
+ def self.load_file(file)
53
+ parse_xml File.read(file)
54
+ end
55
+
56
+ # Load data from the internet.
57
+ # @param [RailFeeds::NationalRail::Credentials] credentials
58
+ # The credentials to authenticate with.
59
+ # @return
60
+ # [Array<RailFeeds::NationalRail::KnowledgeBase::NationalServiceIndicator::TOC>]
61
+ def self.fetch_data(credentials = Credentials)
62
+ fetch(credentials: credentials) do |file|
63
+ parse_xml file.read
64
+ end
65
+ end
66
+
67
+ # rubocop:disable Metrics/AbcSize
68
+ # rubocop:disable Metrics/MethodLength
69
+ def self.parse_xml(xml)
70
+ options = Nokogiri::XML::ParseOptions.new.nonet.noent.noblanks
71
+ doc = Nokogiri::XML.parse(xml, nil, nil, options)
72
+ doc.xpath('/xmlns:NSI/xmlns:TOC').map do |toc_node|
73
+ TOC.new(
74
+ toc_node.xpath('./xmlns:TocCode').first&.content,
75
+ toc_node.xpath('./xmlns:TocName').first&.content,
76
+ Status.new(
77
+ toc_node.xpath('./xmlns:Status').first&.content,
78
+ toc_node.xpath('./xmlns:StatusDescription').first&.content,
79
+ toc_node.xpath('./xmlns:StatusImage').first&.content
80
+ ),
81
+ toc_node.xpath('./xmlns:TwitterAccount').first&.content,
82
+ toc_node.xpath('./xmlns:AdditionalInfo').first&.content,
83
+ toc_node.xpath('./xmlns:ServiceGroup').map do |service_group|
84
+ ServiceGroup.new(
85
+ service_group.xpath('./xmlns:CurrentDisruption').first&.content,
86
+ service_group.xpath('./xmlns:GroupName').first&.content,
87
+ service_group.xpath('./xmlns:CustomDetail').first&.content,
88
+ service_group.xpath('./xmlns:CustomURL').first&.content
89
+ )
90
+ end
91
+ )
92
+ end
93
+ end
94
+ # rubocop:enable Metrics/AbcSize
95
+ # rubocop:enable Metrics/MethodLength
96
+ private_class_method :parse_xml
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailFeeds
4
+ module NationalRail
5
+ module KnowledgeBase # :nodoc:
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailFeeds
4
+ module NationalRail # :nodoc:
5
+ end
6
+ end
7
+
8
+ # Add alias for module
9
+ ::NatRailFeeds = RailFeeds::NationalRail
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'json'
4
-
5
3
  module RailFeeds
6
4
  module NetworkRail
7
5
  # A module for getting information out of the CORPUS data.
@@ -14,15 +12,15 @@ module RailFeeds
14
12
  # @param [RailFeeds::NetworkRail::Credentials] credentials
15
13
  # @param [String] file
16
14
  # The path to the file to save the .json.gz download in.
17
- def self.download(file, credentials: Credentials)
15
+ def self.download(file, credentials = Credentials)
18
16
  client = HTTPClient.new(credentials: credentials)
19
17
  client.download 'ntrod/SupportingFileAuthenticate?type=CORPUS', file
20
18
  end
21
19
 
22
20
  # Fetch the current CORPUS data.
23
21
  # @param [RailFeeds::NetworkRail::Credentials] credentials
24
- # @return [Tempfile]
25
- def self.fetch(credentials: Credentials)
22
+ # @return [IO]
23
+ def self.fetch(credentials = Credentials)
26
24
  client = HTTPClient.new(credentials: credentials)
27
25
  client.fetch 'ntrod/SupportingFileAuthenticate?type=CORPUS'
28
26
  end
@@ -42,7 +40,7 @@ module RailFeeds
42
40
  # @param [RailFeeds::NetworkRail::Credentials] credentials
43
41
  # The credentials to authenticate with.
44
42
  # @return [Array<RailFeeds::NetworkRail::CORPUS::Data>]
45
- def self.fetch_data(credentials: Credentials)
43
+ def self.fetch_data(credentials = Credentials)
46
44
  client = HTTPClient.new(credentials: credentials)
47
45
  client.fetch_unzipped('ntrod/SupportingFileAuthenticate?type=CORPUS') do |file|
48
46
  break parse_json file.read
@@ -69,6 +67,7 @@ module RailFeeds
69
67
 
70
68
  def self.nilify(item)
71
69
  return nil if item.nil? || item.empty?
70
+
72
71
  item
73
72
  end
74
73
  private_class_method :nilify
@@ -6,17 +6,6 @@ module RailFeeds
6
6
  # Can be used to set a global default but create new instances with
7
7
  # specific ones for a specific use.
8
8
  class Credentials < RailFeeds::Credentials
9
- # Get an array of [username, password].
10
- # @return [Array<String>]
11
- def to_a
12
- [username, password]
13
- end
14
-
15
- # Get an array of [username, password].
16
- # @return [Array<String>]
17
- def self.to_a
18
- [username, password]
19
- end
20
9
  end
21
10
  end
22
11
  end
@@ -1,56 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'open-uri'
4
-
5
3
  module RailFeeds
6
4
  module NetworkRail
7
5
  # A wrapper class for ::Net::HTTP
8
- class HTTPClient
9
- include Logging
10
-
11
- HOST = 'datafeeds.networkrail.co.uk'
12
-
13
- # Initialize a new http client.
14
- # @param [RailFeeds::NetworkRail::Credentials] credentials
15
- # The credentials for connecting to the feed.
16
- # @param [Logger] logger
17
- # The logger for outputting evetns, if nil the global logger will be used.
18
- def initialize(credentials: Credentials, logger: nil)
19
- @credentials = credentials
20
- self.logger = logger unless logger.nil?
6
+ class HTTPClient < RailFeeds::HTTPClient
7
+ def initialize(credentials: nil, **args)
8
+ credentials ||= RailFeeds::NetworkRail::Credentials
9
+ super
21
10
  end
22
11
 
23
- # Fetch path from network rail server.
12
+ # Fetch path from server.
24
13
  # @param [String] path The path to fetch.
25
- # @yield [file] Once the block has run the temp file will be deleted.
26
- # @yieldparam [Tempfile] file The content of the file.
14
+ # @yield contents
15
+ # @yieldparam [IO] file Either a Tempfile or StringIO.
27
16
  def fetch(path)
28
- logger.debug "fetch(#{path.inspect})"
29
- uri = URI("https://#{HOST}/#{path}")
30
- yield uri.open(http_basic_authentication: @credentials.to_a)
31
- end
32
-
33
- # Fetch path from network rail server and unzip it.
34
- # @param [String] path The path to fetch.
35
- # @yield [reader] Once the block has run the temp file will be deleted.
36
- # @yieldparam [Zlib::GzipReader] reader The unzippable content of the file.
37
- def fetch_unzipped(path)
38
- logger.debug "get_unzipped(#{path.inspect})"
39
- fetch(path) do |gz_file|
40
- yield Zlib::GzipReader.open(gz_file.path)
41
- end
42
- end
43
-
44
- # Download path from netwrok rail server.
45
- # @param [String] path The path to download.
46
- # @param [String] file The path to the file to save the contents in.
47
- def download(path, file)
48
- logger.debug "download(#{path.inspect}, #{file.inspect})"
49
- fetch(path) do |src|
50
- File.open(file, 'w') do |dst|
51
- IO.copy_stream src, dst
52
- end
53
- end
17
+ super "https://datafeeds.networkrail.co.uk/#{path}"
54
18
  end
55
19
  end
56
20
  end
@@ -181,7 +181,7 @@ module RailFeeds
181
181
  # rubocop:enable Metrics/AbcSize
182
182
 
183
183
  # rubocop:disable Metrics/MethodLength
184
- def to_json
184
+ def to_json(**opts)
185
185
  {
186
186
  'JsonAssociationV1' => {
187
187
  'transaction_type' => 'Create',
@@ -198,7 +198,7 @@ module RailFeeds
198
198
  'diagram_type' => 'T',
199
199
  'CIF_stp_indicator' => stp_indicator_to_cif
200
200
  }
201
- }.to_json
201
+ }.to_json(**opts)
202
202
  end
203
203
  # rubocop:enable Metrics/MethodLength
204
204
  end
@@ -52,7 +52,7 @@ module RailFeeds
52
52
  # @param [IO] file
53
53
  # The file to load data from.
54
54
  def load_cif_file(file)
55
- @parser.parse_cif_file file
55
+ @parser.parse_file file
56
56
 
57
57
  logger.info "Currently have #{associations.count} associations, " \
58
58
  "#{tiplocs.count} tiplocs, #{trains.count} trains."
@@ -92,7 +92,7 @@ module RailFeeds
92
92
  # The credentials for connecting to the feed.
93
93
  # @return [RailFeeds::NetworkRail::Schedule::Header::CIF]
94
94
  # The header of the last file added.
95
- def fetch_data(credentials: Credentials)
95
+ def fetch_data(credentials = Credentials)
96
96
  fetcher = Fetcher.new credentials: credentials
97
97
 
98
98
  method = if last_header.nil? ||
@@ -198,6 +198,7 @@ module RailFeeds
198
198
  trains[train_schedule.uid] ||= []
199
199
  index = trains[train_schedule.uid].index train_schedule
200
200
  return do_train_schedule_create(parser, train_schedule) if index.nil?
201
+
201
202
  trains[train_schedule.uid][index] = train_schedule
202
203
  end
203
204