Module: Toon::Primitives

Defined in:
lib/toon/primitives.rb

Class Method Summary collapse

Class Method Details

.encode_key(key) ⇒ Object

Key encoding



60
61
62
63
64
65
66
# File 'lib/toon/primitives.rb', line 60

def encode_key(key)
  if valid_unquoted_key?(key)
    key
  else
    "#{DOUBLE_QUOTE}#{escape_string(key)}#{DOUBLE_QUOTE}"
  end
end

.encode_primitive(value, delimiter = COMMA) ⇒ Object

Primitive encoding



10
11
12
13
14
15
16
# File 'lib/toon/primitives.rb', line 10

def encode_primitive(value, delimiter = COMMA)
  return NULL_LITERAL if value.nil?
  return value.to_s if value.is_a?(TrueClass) || value.is_a?(FalseClass)
  return value.to_s if value.is_a?(Numeric)

  encode_string_literal(value, delimiter)
end

.encode_string_literal(value, delimiter = COMMA) ⇒ Object



18
19
20
21
22
23
24
# File 'lib/toon/primitives.rb', line 18

def encode_string_literal(value, delimiter = COMMA)
  if safe_unquoted?(value, delimiter)
    value
  else
    "#{DOUBLE_QUOTE}#{escape_string(value)}#{DOUBLE_QUOTE}"
  end
end

.escape_string(value) ⇒ Object



26
27
28
29
30
31
32
33
# File 'lib/toon/primitives.rb', line 26

def escape_string(value)
  value
    .gsub(BACKSLASH, "#{BACKSLASH}#{BACKSLASH}")
    .gsub(DOUBLE_QUOTE, "#{BACKSLASH}#{DOUBLE_QUOTE}")
    .gsub("\n", "#{BACKSLASH}n")
    .gsub("\r", "#{BACKSLASH}r")
    .gsub("\t", "#{BACKSLASH}t")
end

.format_header(length, key: nil, fields: nil, delimiter: COMMA, length_marker: false) ⇒ Object

Header formatters



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/toon/primitives.rb', line 89

def format_header(length, key: nil, fields: nil, delimiter: COMMA, length_marker: false)
  header = ''

  header += encode_key(key) if key

  # Only include delimiter if it's not the default (comma)
  delimiter_suffix = delimiter != DEFAULT_DELIMITER ? delimiter : ''
  length_prefix = length_marker ? length_marker : ''
  header += "[#{length_prefix}#{length}#{delimiter_suffix}]"

  if fields
    quoted_fields = fields.map { |f| encode_key(f) }
    header += "{#{quoted_fields.join(delimiter)}}"
  end

  header += COLON

  header
end

.join_encoded_values(values, delimiter = COMMA) ⇒ Object

Value joining



84
85
86
# File 'lib/toon/primitives.rb', line 84

def join_encoded_values(values, delimiter = COMMA)
  values.map { |v| encode_primitive(v, delimiter) }.join(delimiter)
end

.numeric_like?(value) ⇒ Boolean

Returns:

  • (Boolean)


50
51
52
53
# File 'lib/toon/primitives.rb', line 50

def numeric_like?(value)
  # Match numbers like: 42, -3.14, 1e-6, 05, etc.
  value.match?(/^-?\d+(?:\.\d+)?(?:e[+-]?\d+)?$/i) || value.match?(/^0\d+$/)
end

.padded_with_whitespace?(value) ⇒ Boolean

Returns:

  • (Boolean)


55
56
57
# File 'lib/toon/primitives.rb', line 55

def padded_with_whitespace?(value)
  value != value.strip
end

.safe_unquoted?(value, delimiter = COMMA) ⇒ Boolean

Returns:

  • (Boolean)


35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/toon/primitives.rb', line 35

def safe_unquoted?(value, delimiter = COMMA)
  return false if value.empty?
  return false if padded_with_whitespace?(value)
  return false if value == TRUE_LITERAL || value == FALSE_LITERAL || value == NULL_LITERAL
  return false if numeric_like?(value)
  return false if value.include?(COLON)
  return false if value.include?(DOUBLE_QUOTE) || value.include?(BACKSLASH)
  return false if value.match?(/[\[\]{}]/)
  return false if value.match?(/[\n\r\t]/)
  return false if value.include?(delimiter)
  return false if value.start_with?(LIST_ITEM_MARKER)

  true
end

.valid_unquoted_key?(key) ⇒ Boolean

Returns:

  • (Boolean)


68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/toon/primitives.rb', line 68

def valid_unquoted_key?(key)
  # Keys must not contain control characters or special characters
  return false if key.match?(/[\n\r\t]/)
  return false if key.include?(COLON)
  return false if key.include?(DOUBLE_QUOTE) || key.include?(BACKSLASH)
  return false if key.match?(/[\[\]{}]/)
  return false if key.include?(COMMA)
  return false if key.start_with?(LIST_ITEM_MARKER)
  return false if key.empty?
  return false if key.match?(/^\d+$/)  # Numeric keys
  return false if key != key.strip  # Leading/trailing spaces

  key.match?(/^[A-Z_][\w.]*$/i)
end