module Eddy::Util
Assorted helper functions.
Public Class Methods
Delete all files from a folder; returns number of deleted files.
Fails if the folder contains any symlinks.
@param path [String] Path to the folder. @return [Integer]
# File lib/eddy/util/clean_folder.rb, line 9 def self.clean_folder(path) dir = File.expand_path(path) return 0 unless Dir.exist?(dir) children = Dir.entries(dir).select { |f| File.file?(File.join(dir, f)) } deleted = File.unlink(*children) return deleted end
Directory containing EDI data & definitions. @return [String]
# File lib/eddy/util/paths.rb, line 13 def self.data_dir return File.join(self.root_dir, "data") end
Returns a hash where the keys are Element ids and the values are unprocessed Element names.
@example Example return value
{ "1" => "Route Code", "2" => "Number of Accepted Transaction Sets", "3" => "Free Form Message", "4" => "Air Carrier Code", "5" => "Airport Code", "7" => "Bank Account Number", "8" => "Bank Client Code", "9" => "Late Reason Code", "11" => "Billing Code", ..., }
@return [Hash<String, String>]
# File lib/eddy/util/edi_data.rb, line 38 def self.element_ids() file = File.join(Eddy::Util.data_dir, "elements-short.tsv") data = {} CSV.foreach(file, { col_sep: "\t", quote_char: "\x00", headers: false }) do |row| next if row == ["id", "name"] data[row[0]] = row[1] end return data end
Return the full name of an Element with the given id.
@example
Eddy::Util.element_name_by_id("93") #=> "Name"
@param id [String] ID of the Element to look up. @return [Hash]
# File lib/eddy/util/edi_data.rb, line 80 def self.element_name_by_id(id) data = Eddy::Util.element_ids() return data[id] if data.key?(id) raise Eddy::Errors::Error, "No element found with id #{id}" end
List names of Elements
with Ruby files currently in `Eddy.config.build_dir/elements`.
@example
Eddy::Util.list_built_elements() #=> []
@return [Array<String>]
# File lib/eddy/util/edi_data.rb, line 145 def self.list_built_elements() dir = File.join(Eddy.config.build_dir, "elements", "**", "*.rb") files = Dir.glob(dir) return files.map { |f| File.basename(f).sub(/\..*/, "").upcase } end
List the names of Elements
for which Ruby classes have already been built.
@example
Eddy::Util.list_element_classes() #=> ["166", "326", "349", "234", ...]
@return [Array<String>]
# File lib/eddy/util/edi_data.rb, line 105 def self.list_element_classes() dir = File.join(Eddy::Util.root_dir, "lib", "definitions", "elements", "**", "*.rb") files = Dir.glob(dir) return files.map { |f| File.basename(f).sub(/\..*/, "").upcase } end
List the names of Segments
for which Ruby classes have already been built.
@example
Eddy::Util.list_segment_classes() #=> ["TD5", "N4", "TD1", "BIG", ...]
@return [Array<String>]
# File lib/eddy/util/edi_data.rb, line 117 def self.list_segment_classes() dir = File.join(Eddy::Util.root_dir, "lib", "definitions", "segments", "**", "*.rb") files = Dir.glob(dir) return files.map { |f| File.basename(f).sub(/\..*/, "").upcase } end
List Segment definition files in `data/segments`.
@example Example return value
[ "~/.rbenv/versions/2.6.5/lib/gems/eddy-0.0.0/data/segments/ack.segment.yml", "~/.rbenv/versions/2.6.5/lib/gems/eddy-0.0.0/data/segments/bak.segment.yml", ..., ]
@return [Array<String>]
# File lib/eddy/util/edi_data.rb, line 133 def self.list_segment_definitions() dir = File.join(Eddy::Util.data_dir, "segments") files = Dir.entries(dir).select { |f| File.file?(File.join(dir, f)) } return files.map { |f| File.join(dir, f) }.sort end
Given an array of numbers, returns the lowest number not included in the array.
@param existing [Array<Integer>] @return [Integer]
# File lib/eddy/util/new_number.rb, line 8 def self.new_number(existing) n = nil i = 1 loop do if existing.include?(i) i += 1 next else n = i break end end return n end
Given an Element Id (positive number under 1688, or I01-I64), returns a string sutable for use as a Ruby class name.
@param id [String] @return [String]
# File lib/eddy/util/normalize.rb, line 9 def self.normalize_id(id) name_regex = /\A(?<prefix>[iI]{1})?(?<numbers>\d+)\Z/ res = "" if matches = id.match(name_regex) if matches[:prefix] res << "I" else res << "E" end res << matches[:numbers] else raise Eddy::Errors::BuildError, "invalid element id" end end
Convert a string to [PascalCase](wiki.c2.com/?PascalCase), or UpperCamelCase Remove dashes, slashes, underscores, spaces, periods, and parens from a string then titleize it.
@param name [String] @return [String]
# File lib/eddy/util/normalize.rb, line 29 def self.normalize_name(name) return name.gsub(/\s*\(.*\)|[']/, "") .gsub(%r{[.,_\-/]}, " ") .split(" ") .map(&:capitalize) .join("") end
Read a TSV file and return its contents as an array of hashes.
@param filepath [String] Path to the TSV file. @return [Array<Hash{Symbol => String}>]
# File lib/eddy/util/read.rb, line 12 def self.parse_tsv(filepath) return CSV.read( filepath, col_sep: "\t", headers: true, quote_char: "\x00", header_converters: :symbol, ).map(&:to_hash) end
Return raw data from `data/elements.tsv`.
@example Example return value
[ {:id=>"1", :name=>"Route Code", :type=>"AN", :min=>"1", :max=>"13", :description=>"Mutually defined route code"}, {:id=>"2", :name=>"Number of Accepted Transaction Sets", :type=>"N0", :min=>"1", :max=>"6", :description=>"Number of accepted Transaction Sets in a Functional Group"}, {:id=>"3", :name=>"Free Form Message", :type=>"AN", :min=>"1", :max=>"60", :description=>"Free-form text"}, ..., ]
@return [Array<Hash>]
# File lib/eddy/util/edi_data.rb, line 17 def self.raw_element_data() return Eddy::Util.parse_tsv(File.join(Eddy::Util.data_dir, "elements.tsv")) end
Read data in from either a JSON or YAML file.
@param path [String] Path to the file. @param symbolize [Boolean] (true) @return [Hash{Symbol => Object}]
# File lib/eddy/util/read.rb, line 27 def self.read_json_or_yaml(path, symbolize: true) path = File.expand_path(path) data = case File.extname(path).downcase when /\.ya?ml/ then YAML.safe_load(File.read(path), symbolize_names: symbolize) when ".json" then JSON.parse(File.read(path), symbolize_names: symbolize) else raise Eddy::Errors::Error end return data end
Directory where the gem is located. @return [String]
# File lib/eddy/util/paths.rb, line 7 def self.root_dir return File.expand_path("../../../..", __FILE__) end
Returns a hash where the keys are Segment ids and the values are unprocessed Segment names.
@example Example return value
{ "AAA" => "Request Validation", "ACD" => "Account Description", "ACK" => "Line Item Acknowledgment", "ACS" => "Ancillary Charges", "ACT" => "Account Identification", "AD1" => "Adjustment Amount", "ADI" => "Animal Disposition", ..., }
@return [Hash<String, String>]
# File lib/eddy/util/edi_data.rb, line 63 def self.segment_ids() file = File.join(Eddy::Util.data_dir, "segments.tsv") data = {} CSV.foreach(file, { col_sep: "\t", quote_char: "\x00" }) do |row| next if row == ["id", "name"] data[row[0]] = row[1] end return data end
Return the full name of a Segment with the given id.
@example
Eddy::Util.segment_name_by_id("N2") #=> "Additional Name Information"
@param id [String] ID of the Segment to look up. @return [Hash]
# File lib/eddy/util/edi_data.rb, line 93 def self.segment_name_by_id(id) data = Eddy::Util.segment_ids() return data[id] if data.key?(id) raise Eddy::Errors::Error, "No segment found with id #{id}" end
Convert a string to [snake_case](en.wikipedia.org/wiki/Snake_case)
@param name [String] @return [String]
# File lib/eddy/util/normalize.rb, line 41 def self.snake_case(name) return name.gsub(/\s*\(.*\)|['.]/, "") .gsub(%r{[,_\-/]}, " ") .split(" ") .map(&:downcase) .join("_") end
@return [String]
# File lib/eddy/util/timestamp.rb, line 7 def self.timestamp return ::Time.now.strftime("%m-%d-%Y-%H-%M-%S") end
See: [Trailing delimiters and 999 response - X12 RFI](www.x12.org/rfis/Trailing%20delimiters%20and%20999%20response.pdf)
@param itch [String] String containing an EDI Interchange. @param element_separator [String] (“*”) @param segment_separator [String] (“~”) @return [String]
# File lib/eddy/util/trim.rb, line 11 def self.trim_delims_from_interchange(itch, element_separator: "*", segment_separator: "~") e_sep = Regexp.escape(element_separator) s_sep = Regexp.escape(segment_separator) return itch.gsub(/#{e_sep}+(?=#{s_sep})/, "") end
See: [Trailing delimiters and 999 response - X12 RFI](www.x12.org/rfis/Trailing%20delimiters%20and%20999%20response.pdf)
@param segment [String] String containing an EDI segment. @param separator [String] (“*”) @return [String]
# File lib/eddy/util/trim.rb, line 22 def self.trim_delims_from_segment(segment, separator: "*") e_sep = Regexp.escape(separator) return segment.gsub(/#{e_sep}+(?=$)/, "") end