Class: Metaclean::Runner

Inherits:
Object
  • Object
show all
Defined in:
lib/metaclean/runner.rb

Instance Method Summary collapse

Constructor Details

#initialize(options) ⇒ Runner

Constructor — just stashes the options Hash. The CLI builds it.



23
24
25
# File 'lib/metaclean/runner.rb', line 23

def initialize(options)
  @options = options
end

Instance Method Details

#clean_paths(paths) ⇒ Object



51
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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/metaclean/runner.rb', line 51

def clean_paths(paths)
  files = expand_files(paths)
  return Display.warning('No files to process.') if files.empty?

  announce_tools

  # Confirmation prompt — skipped for --force and --dry-run (since
  # dry-run never modifies anything anyway).
  unless @options[:force] || @options[:dry_run]
    action = @options[:in_place] ? 'OVERWRITE' : 'create cleaned copies of'
    puts Display.c("About to #{action} #{files.size} file(s).", :yellow)
    if @options[:in_place] && !@options[:no_backup]
      puts Display.c('Backups will be saved alongside as <file>.bak.', :gray)
    end
    print Display.c('Proceed? [y/N] ', :bold)
    # `&.` is the safe-navigation operator: if `gets` returns nil
    # (e.g. user hit Ctrl-D), the chain short-circuits to nil.
    ans = $stdin.gets&.strip&.downcase
    return Display.warning('Aborted.') unless %w[y yes].include?(ans)
  end

  summary = { cleaned: 0, failed: 0, removed_total: 0, residual_files: 0 }

  # `each_with_index` gives us the file AND its position. We pass both
  # to `clean_one` so it can render "[3/47]" in batch mode.
  files.each_with_index do |file, idx|
    result = clean_one(file, index: idx + 1, total: files.size)
    summary[result[:status]] += 1
    summary[:removed_total]  += result[:removed].to_i
    summary[:residual_files] += 1 if result[:residual].to_i.positive?
  rescue Error => e
    # Block-level rescue (Ruby 2.5+). Catches errors from `clean_one`
    # without aborting the whole batch — one bad file shouldn't stop
    # the next 99 from being cleaned.
    warn Display.error("#{file}: #{e.message}")
    summary[:failed] += 1
  end

  print_summary(summary)

  # Non-zero exit code so CI pipelines can detect failures.
  exit 1 if @options[:strict_verify] && summary[:residual_files].positive?
  exit 1 if summary[:failed].positive?
end

#inspect_paths(paths) ⇒ Object

─────────────────────────────────────────────────────────────────Public entry points: one for ‘–inspect`, one for the cleaning flow. ─────────────────────────────────────────────────────────────────



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/metaclean/runner.rb', line 31

def inspect_paths(paths)
  files = expand_files(paths)
  return Display.warning('No files to inspect.') if files.empty?

  # `--json`: machine output, no colors, suitable for piping.
  if @options[:format] == :json
    out = files.map { |f| { file: f, metadata: Exiftool.read(f) } }
    puts JSON.pretty_generate(out)
    return
  end

  # Human output: pretty header + grouped table per file.
  files.each do |file|
    Display.header "📄 #{file}"
    meta = Exiftool.read(file)
    Display.section "Metadata (#{Display.count_embedded(meta)} embedded tags)"
    Display.(meta)
  end
end