Module: LanguageOperator::CLI::Formatters::ValueFormatter

Defined in:
lib/language_operator/cli/formatters/value_formatter.rb

Overview

Utility module for formatting values (time, duration, file sizes, etc.) for display in CLI output. Provides consistent formatting across commands.

Constant Summary collapse

SECONDS_PER_MINUTE =
60
SECONDS_PER_HOUR =
3600
SECONDS_PER_DAY =
86_400
SECONDS_PER_WEEK =
604_800
BYTES_PER_KB =
1024
BYTES_PER_MB =
1024 * 1024
BYTES_PER_GB =
1024 * 1024 * 1024

Class Method Summary collapse

Class Method Details

.duration(seconds) ⇒ String

Format a duration in seconds

Examples:

ValueFormatter.duration(0.5) # => "500ms"
ValueFormatter.duration(90) # => "1m 30s"

Parameters:

  • seconds (Numeric)

    Duration in seconds

Returns:

  • (String)

    Formatted string like "1.5s" or "2m 30s"



89
90
91
92
93
94
95
96
97
98
99
# File 'lib/language_operator/cli/formatters/value_formatter.rb', line 89

def self.duration(seconds)
  if seconds < 1
    "#{(seconds * 1000).round}ms"
  elsif seconds < SECONDS_PER_MINUTE
    "#{seconds.round(1)}s"
  else
    minutes = (seconds / SECONDS_PER_MINUTE).floor
    secs = (seconds % SECONDS_PER_MINUTE).round
    "#{minutes}m #{secs}s"
  end
end

.file_size(bytes) ⇒ String

Format file size in bytes to human-readable format

Examples:

ValueFormatter.file_size(1500) # => "1.5KB"

Parameters:

  • bytes (Integer)

    File size in bytes

Returns:

  • (String)

    Formatted string like "1.5KB" or "2.3MB"



108
109
110
111
112
113
114
115
116
117
118
# File 'lib/language_operator/cli/formatters/value_formatter.rb', line 108

def self.file_size(bytes)
  if bytes < BYTES_PER_KB
    "#{bytes}B"
  elsif bytes < BYTES_PER_MB
    "#{(bytes / BYTES_PER_KB.to_f).round(1)}KB"
  elsif bytes < BYTES_PER_GB
    "#{(bytes / BYTES_PER_MB.to_f).round(1)}MB"
  else
    "#{(bytes / BYTES_PER_GB.to_f).round(1)}GB"
  end
end

.log_time(time) ⇒ String

Format Time object as HH:MM:SS for logs

Examples:

ValueFormatter.log_time(Time.now) # => "14:30:25"

Parameters:

  • time (Time)

    The time to format

Returns:

  • (String)

    Formatted string like "14:30:25"



154
155
156
# File 'lib/language_operator/cli/formatters/value_formatter.rb', line 154

def self.log_time(time)
  time.strftime('%H:%M:%S')
end

.parse_and_format_time(timestamp_str) ⇒ String

Parse timestamp string and format as HH:MM:SS

Examples:

ValueFormatter.parse_and_format_time("2025-01-15T14:30:25Z") # => "14:30:25"

Parameters:

  • timestamp_str (String)

    ISO or text format timestamp

Returns:

  • (String)

    Formatted time or empty string on parse error



165
166
167
168
169
170
171
172
# File 'lib/language_operator/cli/formatters/value_formatter.rb', line 165

def self.parse_and_format_time(timestamp_str)
  return '' unless timestamp_str

  time = Time.parse(timestamp_str)
  log_time(time)
rescue StandardError
  ''
end

.schedule_time(hours, minutes) ⇒ String

Format time components as HH:MM for schedules

Examples:

ValueFormatter.schedule_time(14, 30) # => "14:30"

Parameters:

  • hours (Integer)

    Hours (0-23)

  • minutes (Integer)

    Minutes (0-59)

Returns:

  • (String)

    Formatted string like "14:30"



182
183
184
# File 'lib/language_operator/cli/formatters/value_formatter.rb', line 182

def self.schedule_time(hours, minutes)
  format('%<hours>02d:%<minutes>02d', hours: hours, minutes: minutes)
end

.time_ago(past_time) ⇒ String

Format time elapsed since past time (opposite of time_until)

Examples:

ValueFormatter.time_ago(Time.now - 300) # => "5m ago"

Parameters:

  • past_time (Time)

    Past timestamp

Returns:

  • (String)

    Formatted string like "5m ago" or "2h 15m ago"



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/language_operator/cli/formatters/value_formatter.rb', line 52

def self.time_ago(past_time)
  diff = Time.now - past_time

  if diff < 0
    'in the future' # Edge case for clock skew
  elsif diff < SECONDS_PER_MINUTE
    "#{diff.to_i}s ago"
  elsif diff < SECONDS_PER_HOUR
    minutes = (diff / SECONDS_PER_MINUTE).to_i
    "#{minutes}m ago"
  elsif diff < SECONDS_PER_DAY
    hours = (diff / SECONDS_PER_HOUR).to_i
    minutes = ((diff % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE).to_i
    if minutes > 0
      "#{hours}h #{minutes}m ago"
    else
      "#{hours}h ago"
    end
  else
    days = (diff / SECONDS_PER_DAY).to_i
    hours = ((diff % SECONDS_PER_DAY) / SECONDS_PER_HOUR).to_i
    if hours > 0
      "#{days}d #{hours}h ago"
    else
      "#{days}d ago"
    end
  end
end

.time_until(future_time) ⇒ String

Format time until a future event

Examples:

ValueFormatter.time_until(Time.now + 300) # => "in 5m"

Parameters:

  • future_time (Time)

    The future time

Returns:

  • (String)

    Formatted string like "in 5m" or "in 2h 15m"



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/language_operator/cli/formatters/value_formatter.rb', line 24

def self.time_until(future_time)
  diff = future_time - Time.now

  if diff.negative?
    'overdue'
  elsif diff < SECONDS_PER_MINUTE
    "in #{diff.to_i}s"
  elsif diff < SECONDS_PER_HOUR
    minutes = (diff / SECONDS_PER_MINUTE).to_i
    "in #{minutes}m"
  elsif diff < SECONDS_PER_DAY
    hours = (diff / SECONDS_PER_HOUR).to_i
    minutes = ((diff % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE).to_i
    "in #{hours}h #{minutes}m"
  else
    days = (diff / SECONDS_PER_DAY).to_i
    hours = ((diff % SECONDS_PER_DAY) / SECONDS_PER_HOUR).to_i
    "in #{days}d #{hours}h"
  end
end

.timestamp(time) ⇒ String

Format a timestamp as relative time or absolute date

Examples:

ValueFormatter.timestamp(Time.now - 300) # => "5 minutes ago"

Parameters:

  • time (Time)

    The timestamp to format

Returns:

  • (String)

    Formatted string like "5 minutes ago" or "2025-01-15 14:30"



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/language_operator/cli/formatters/value_formatter.rb', line 127

def self.timestamp(time)
  now = Time.now
  diff = now - time

  if diff < SECONDS_PER_MINUTE
    "#{diff.to_i} seconds ago"
  elsif diff < SECONDS_PER_HOUR
    minutes = (diff / SECONDS_PER_MINUTE).to_i
    "#{minutes} minute#{'s' if minutes != 1} ago"
  elsif diff < SECONDS_PER_DAY
    hours = (diff / SECONDS_PER_HOUR).to_i
    "#{hours} hour#{'s' if hours != 1} ago"
  elsif diff < SECONDS_PER_WEEK
    days = (diff / SECONDS_PER_DAY).to_i
    "#{days} day#{'s' if days != 1} ago"
  else
    time.strftime('%Y-%m-%d %H:%M')
  end
end