Class: Kotoshu::Cli::CacheCommand

Inherits:
Thor
  • Object
show all
Defined in:
lib/kotoshu/cli/cache_command.rb

Overview

Cache management CLI — wired as kotoshu cache <subcommand> in cli.rb.

Operates on the disk-backed Cache::LanguageCache. Reads and writes go through the real cache API (available?, cached_resources, clear_all, clear, clean, stats, get_spelling, get_grammar, frequency_available?, language_info). Kelly frequency data lives in a separate Cache::FrequencyCache.

Instance Method Summary collapse

Instance Method Details

#cleanObject



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/kotoshu/cli/cache_command.rb', line 84

def clean
  cache = create_cache

  if options[:dry_run]
    stats = cache.stats
    puts "Dry run — no changes made"
    puts "  Cached resources: #{stats[:cached_resources].size}"
    puts "  Size: #{format_bytes(stats[:size_bytes])}"
    return
  end

  result = cache.clean
  puts "Cache cleaned:"
  puts "  Expired entries removed: #{result[:expired_entries_removed]}"
  puts "  Bytes reclaimed: #{format_bytes(result[:bytes_reclaimed])}"
end

#create_cacheObject

Construct a LanguageCache honoring the --cache_path option.

Public so specs can substitute a cache with a temp directory.



191
192
193
194
195
# File 'lib/kotoshu/cli/cache_command.rb', line 191

def create_cache
  opts = {}
  opts[:cache_path] = options[:cache_path] if options[:cache_path]
  Cache::LanguageCache.new(**opts)
end

#download(language) ⇒ Object



142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/kotoshu/cli/cache_command.rb', line 142

def download(language)
  cache = create_cache
  type = options[:type]

  case type
  when "spelling"
    result = cache.get_spelling(language, force_download: options[:force])
    puts "Spelling dictionary for '#{language}' at #{File.dirname(result[:dic_path])}"
  when "grammar"
    result = cache.get_grammar(language, force_download: options[:force])
    puts "Grammar rules for '#{language}' at #{result[:rules_path]}"
  when "frequency"
    freq = Cache::FrequencyCache.new(cache_path: frequency_cache_path(cache))
    result = freq.get_frequency(language, force_download: options[:force])
    puts "Frequency data for '#{language}' at #{result[:frequency_path]}"
  else
    raise Errors::UsageError, "Unknown --type: #{type}"
  end
end

#evictObject



106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/kotoshu/cli/cache_command.rb', line 106

def evict
  cache = create_cache
  plan = cache.evict(dry_run: options[:dry_run])

  if options[:dry_run]
    if plan[:evict].empty?
      puts "Nothing to evict — cache is under the size cap"
      return
    end

    puts "Dry run — no changes made"
    puts "Would evict #{plan[:evict].size} entries, " \
         "reclaiming #{format_bytes(plan[:bytes_reclaimed])}:"
    print_eviction_list(plan[:evict])
    return
  end

  if plan[:evict].empty?
    puts "Nothing to evict — cache is under the size cap"
    return
  end

  puts "Evicted #{plan[:evict].size} entries, " \
       "reclaimed #{format_bytes(plan[:bytes_reclaimed])}:"
  print_eviction_list(plan[:evict])
end

#format_bytes(bytes) ⇒ String

Format bytes as a human-readable string with one decimal place.

Parameters:

  • bytes (Integer, nil)

    Bytes

Returns:

  • (String)

    Formatted string



201
202
203
204
205
206
207
# File 'lib/kotoshu/cli/cache_command.rb', line 201

def format_bytes(bytes)
  return "0 B" if bytes.nil? || bytes.zero?

  units = %w[B KB MB GB TB]
  exp = [Math.log(bytes, 1024).floor, units.size - 1].min
  "#{format('%.1f', bytes.to_f / (1024**exp))} #{units[exp]}"
end

#infoObject



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/kotoshu/cli/cache_command.rb', line 55

def info
  cache = create_cache
  stats = cache.stats

  if options[:json]
    puts JSON.pretty_generate(
      hits: stats[:hits],
      misses: stats[:misses],
      size: stats[:size_bytes],
      hit_rate: stats[:hit_rate],
      cached_resources: stats[:cached_resources],
      location: cache.cache_path
    )
    return
  end

  puts "Cache Statistics"
  puts "  Location: #{cache.cache_path}"
  puts "  Languages cached: #{cached_languages(cache).size}"
  puts "  Size: #{format_bytes(stats[:size_bytes])}"
  puts "  Hits: #{stats[:hits]}, Misses: #{stats[:misses]}"
  puts "  Hit rate: #{(stats[:hit_rate] * 100).round(1)}%"
end

#listObject



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/kotoshu/cli/cache_command.rb', line 32

def list
  cache = create_cache
  languages = cached_languages(cache)

  if options[:json]
    puts JSON.pretty_generate(languages: languages)
    return
  end

  if languages.empty?
    puts "No cached languages found"
    return
  end

  puts "Cached languages:"
  languages.each { |lang| puts "  #{lang}" }
end

#purgeObject



167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/kotoshu/cli/cache_command.rb', line 167

def purge
  cache = create_cache

  unless options[:confirm]
    print "This will remove all cached dictionaries and frequency data. [y/N] "
    response = $stdin.gets
    return unless response && response.chomp =~ /\A[yY]\z/
  end

  cache.clear_all
  puts "Cache purged"
end

#time_ago(iso_time) ⇒ String

Human-readable "time ago" string for an ISO8601 timestamp.

Parameters:

  • iso_time (String, nil)

    ISO8601 timestamp

Returns:

  • (String)

    Time ago string



213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
# File 'lib/kotoshu/cli/cache_command.rb', line 213

def time_ago(iso_time)
  return "unknown" unless iso_time

  time = Time.iso8601(iso_time)
  seconds = Time.now - time

  return "just now" if seconds < 60

  minutes = (seconds / 60).to_i
  return "#{minutes}m ago" if minutes < 60

  hours = (minutes / 60).to_i
  return "#{hours}h ago" if hours < 24

  days = (hours / 24).to_i
  return "#{days}d ago" if days < 30

  months = (days / 30).to_i
  return "#{months}mo ago" if months < 12

  years = (months / 12).to_i
  "#{years}y ago"
end

#validate(language) ⇒ Object



181
182
183
184
185
186
# File 'lib/kotoshu/cli/cache_command.rb', line 181

def validate(language)
  cache = create_cache
  puts "Validating #{language}"
  puts "  Spelling: #{resource_status(cache, language, 'spelling')}"
  puts "  Grammar: #{resource_status(cache, language, 'grammar')}"
end