Module: Eddy::Util

Defined in:
lib/eddy/util.rb,
lib/eddy/util/read.rb,
lib/eddy/util/time.rb,
lib/eddy/util/trim.rb,
lib/eddy/util/paths.rb,
lib/eddy/util/edi_data.rb,
lib/eddy/util/normalize.rb,
lib/eddy/util/timestamp.rb,
lib/eddy/util/new_number.rb,
lib/eddy/util/clean_folder.rb

Overview

Assorted helper functions.

Defined Under Namespace

Modules: Time

Normalize collapse

Paths collapse

EDI Data collapse

Class Method Summary collapse

Class Method Details

.clean_folder(path) ⇒ Integer

Delete all files from a folder; returns number of deleted files.

Fails if the folder contains any symlinks.

Parameters:

  • path (String)

    Path to the folder.

Returns:

  • (Integer)


9
10
11
12
13
14
15
# 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

.data_dirString

Directory containing EDI data & definitions.

Returns:

  • (String)


13
14
15
# File 'lib/eddy/util/paths.rb', line 13

def self.data_dir
  return File.join(self.root_dir, "data")
end

.element_idsHash<String, String>

Returns a hash where the keys are Element ids and the values are unprocessed Element names.

Examples:

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",
  ...,
}

Returns:

  • (Hash<String, String>)


38
39
40
41
42
43
44
45
46
# 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

.element_name_by_id(id) ⇒ Hash

Return the full name of an Element with the given id.

Examples:

Eddy::Util.element_name_by_id("93") #=> "Name"

Parameters:

  • id (String)

    ID of the Element to look up.

Returns:

  • (Hash)

Raises:



80
81
82
83
84
# 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_built_elementsArray<String>

List names of Elements with Ruby files currently in Eddy.config.build_dir/elements.

Examples:

Eddy::Util.list_built_elements() #=> []

Returns:

  • (Array<String>)


145
146
147
148
149
# 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_element_classesArray<String>

List the names of Elements for which Ruby classes have already been built.

Examples:

Eddy::Util.list_element_classes() #=> ["166", "326", "349", "234", ...]

Returns:

  • (Array<String>)


105
106
107
108
109
# 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_segment_classesArray<String>

List the names of Segments for which Ruby classes have already been built.

Examples:

Eddy::Util.list_segment_classes() #=> ["TD5", "N4", "TD1", "BIG", ...]

Returns:

  • (Array<String>)


117
118
119
120
121
# 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_definitionsArray<String>

List Segment definition files in data/segments.

Examples:

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",
  ...,
]

Returns:

  • (Array<String>)


133
134
135
136
137
# 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

.new_number(existing) ⇒ Integer

Given an array of numbers, returns the lowest number not included in the array.

Parameters:

  • existing (Array<Integer>)

Returns:

  • (Integer)


8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 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

.normalize_id(id) ⇒ String

Given an Element Id (positive number under 1688, or I01-I64), returns a string sutable for use as a Ruby class name.

Parameters:

  • id (String)

Returns:

  • (String)


9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 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

.normalize_name(name) ⇒ String

Convert a string to PascalCase, or UpperCamelCase Remove dashes, slashes, underscores, spaces, periods, and parens from a string then titleize it.

Parameters:

  • name (String)

Returns:

  • (String)


29
30
31
32
33
34
35
# File 'lib/eddy/util/normalize.rb', line 29

def self.normalize_name(name)
  return name.gsub(/\s*\(.*\)|[']/, "")
             .gsub(%r{[.,_\-/]}, " ")
             .split(" ")
             .map(&:capitalize)
             .join("")
end

.parse_tsv(filepath) ⇒ Array<Hash{Symbol => String}>

Read a TSV file and return its contents as an array of hashes.

Parameters:

  • filepath (String)

    Path to the TSV file.

Returns:

  • (Array<Hash{Symbol => String}>)


12
13
14
15
16
17
18
19
20
# 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

.raw_element_dataArray<Hash>

Return raw data from data/elements.tsv.

Examples:

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"},
  ...,
]

Returns:

  • (Array<Hash>)


17
18
19
# 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_json_or_yaml(path, symbolize: true) ⇒ Hash{Symbol => Object}

Read data in from either a JSON or YAML file.

Parameters:

  • path (String)

    Path to the file.

  • symbolize (Boolean) (defaults to: true)

    (true)

Returns:

  • (Hash{Symbol => Object})


27
28
29
30
31
32
33
34
35
# 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

.root_dirString

Directory where the gem is located.

Returns:

  • (String)


7
8
9
# File 'lib/eddy/util/paths.rb', line 7

def self.root_dir
  return File.expand_path("../../../..", __FILE__)
end

.segment_idsHash<String, String>

Returns a hash where the keys are Segment ids and the values are unprocessed Segment names.

Examples:

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",
  ...,
}

Returns:

  • (Hash<String, String>)


63
64
65
66
67
68
69
70
71
# 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

.segment_name_by_id(id) ⇒ Hash

Return the full name of a Segment with the given id.

Examples:

Eddy::Util.segment_name_by_id("N2") #=> "Additional Name Information"

Parameters:

  • id (String)

    ID of the Segment to look up.

Returns:

  • (Hash)

Raises:



93
94
95
96
97
# 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

.snake_case(name) ⇒ String

Convert a string to snake_case

Parameters:

  • name (String)

Returns:

  • (String)


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

def self.snake_case(name)
  return name.gsub(/\s*\(.*\)|['.]/, "")
             .gsub(%r{[,_\-/]}, " ")
             .split(" ")
             .map(&:downcase)
             .join("_")
end

.timestampString

Returns:

  • (String)


7
8
9
# File 'lib/eddy/util/timestamp.rb', line 7

def self.timestamp
  return ::Time.now.strftime("%m-%d-%Y-%H-%M-%S")
end

.trim_delims_from_interchange(itch, element_separator: "*", segment_separator: "~") ⇒ String

Parameters:

  • itch (String)

    String containing an EDI Interchange.

  • element_separator (String) (defaults to: "*")

    ("*")

  • segment_separator (String) (defaults to: "~")

    ("~")

Returns:

  • (String)


11
12
13
14
15
# 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

.trim_delims_from_segment(segment, separator: "*") ⇒ String

Parameters:

  • segment (String)

    String containing an EDI segment.

  • separator (String) (defaults to: "*")

    ("*")

Returns:

  • (String)


22
23
24
25
# 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