class DOST::Data

Attributes

headers_delimiters[R]
key_modifier[R]
lines[R]
values_delimiters[R]

Public Class Methods

new(lines:, headers_delimiters:, values_delimiters:, key_modifier: nil) click to toggle source
# File lib/dost.rb, line 5
def initialize(lines:, headers_delimiters:, values_delimiters:, key_modifier: nil)
  @lines = lines.map(&:chomp)
  @headers_delimiters = headers_delimiters
  @values_delimiters = values_delimiters
  @key_modifier = key_modifier
end

Public Instance Methods

dynamic_offseted_values(left_dynamic_bound_headers = []) click to toggle source
# File lib/dost.rb, line 20
def dynamic_offseted_values(left_dynamic_bound_headers = [])
  values_lines.map do |line|
    headers.reverse.map do |(name, range)|
      is_dynamic = left_dynamic_bound_headers.include?(name)
      str = line[range]
      if is_dynamic && range.first > 0
        i = range.first - 1
        while present?(line[i]) && i >= 0 do
          str.prepend(line[i])
          line[i] = ' '
          i -= 1
        end
      end
      [name, str.strip]
    end.reverse.to_h
  end
end
headers() click to toggle source
# File lib/dost.rb, line 12
def headers
  @headers ||= parse_headers
end
values() click to toggle source
# File lib/dost.rb, line 16
def values
  @values ||= parse_values
end

Private Instance Methods

blank?(str) click to toggle source
# File lib/dost.rb, line 119
        def blank?(str)
  str !~ /[^[:space:]]/
end
calc_ranges(header_line) click to toggle source
# File lib/dost.rb, line 77
        def calc_ranges(header_line)
  header_line.split(%r{(^\s*\S*\s*)|(\S*\s*)}).reject(&:empty?).reduce([]) do |acc, key|
    index = acc.last&.last&.last || -1;
    acc.push([key, (index + 1)..(index + key.length)])
  end
end
delimiter?(line) click to toggle source
# File lib/dost.rb, line 111
        def delimiter?(line)
  line.chars.uniq.count == 1 && present?(delimiter_char(line))
end
delimiter_char(line) click to toggle source
# File lib/dost.rb, line 115
        def delimiter_char(line)
  line.chars.uniq.first
end
header_lines() click to toggle source
# File lib/dost.rb, line 88
        def header_lines
  lines_between_delimiters(headers_delimiters.first, headers_delimiters.last)
end
lines_between_delimiters(delimiter_start, delimiter_end) click to toggle source
# File lib/dost.rb, line 92
        def lines_between_delimiters(delimiter_start, delimiter_end)
  lines.reduce([]) do |acc, line|
    if acc.empty?
      acc.push(line) if delimiter?(line) && delimiter_char(line) == delimiter_start
    else
      if delimiter?(line)
        if delimiter_char(line) == delimiter_end
          return acc[1..-1]
        else
          acc = [line]
        end
      else
        acc.push(line)
      end
    end
    acc
  end
end
modify_key(key) click to toggle source
# File lib/dost.rb, line 132
        def modify_key(key)
  key_modifier.nil? ? keyа : key_modifier.call(key)
end
overlaps?(orig, other) click to toggle source

from apidock.com/rails/Range/overlaps

# File lib/dost.rb, line 128
        def overlaps?(orig, other)
  orig.cover?(other.first) || other.cover?(orig.first)
end
parse_headers() click to toggle source
# File lib/dost.rb, line 38
        def parse_headers
  raw_headers = header_lines.map { |header_line| calc_ranges(header_line) }

  first_row = raw_headers.first
  second_row = raw_headers[1]

  first_row.map.with_index do |(first_key, first_range)|
    values_inside = second_row.select do |(second_key, second_range)|
      overlaps?(
        ((second_range.first + second_key.index(/(\S)/))..(second_key.strip.length + second_range.first)),
        (first_range.first..(first_key.strip.length + first_range.first))
      )
    end

    if values_inside.empty?
      [[modify_key(first_key), first_range]]
    else
      values_inside.map.with_index do |(second_item_key, second_item_range), index|
        key = (first_key.strip + second_item_key.strip.prepend('_'))
        is_last_item = (index == values_inside.count - 1)
        second_item_left_bound = second_item_range.first + second_item_key.index(/(\S)/)
        left_bound = index.zero? ? [second_item_left_bound, first_range.first].min : second_item_range.first
        right_bound = is_last_item ? [second_item_range.last, first_range.last].min : second_item_range.last

        range = left_bound..right_bound
        [modify_key(key), range]
      end
    end
  end.flatten(1)
end
parse_values() click to toggle source
# File lib/dost.rb, line 69
        def parse_values
  values_lines.map do |line|
    headers.map do |(name, range)|
      [name, line[range].strip]
    end.to_h
  end
end
present?(str) click to toggle source
# File lib/dost.rb, line 123
        def present?(str)
  !blank?(str)
end
values_lines() click to toggle source
# File lib/dost.rb, line 84
        def values_lines
  lines_between_delimiters(values_delimiters.first, values_delimiters.last)
end