Module: Elect::Processor

Defined in:
lib/elect/processor.rb

Overview

文件与目录扫描处理器。

职责:

- 遍历目录树,找出所有文本类文件
- 逐文件读取、检测水印、按选项清理或仅报告
- 输出统计信息

Defined Under Namespace

Classes: Result

Constant Summary collapse

DEFAULT_EXTS =

默认扫描的文件扩展名

%w[
  .md .txt .py .rb .js .ts .tsx .jsx .java .go .rs
  .c .h .cpp .hpp .cc .cs .php .swift .kt .scala
  .html .css .scss .less .vue .svelte
  .json .yaml .yml .toml .xml .sql .sh .bat .ps1
  .tex .rst .adoc .org .csv .tsv .ini .conf .cfg
].freeze

Class Method Summary collapse

Class Method Details

.process_dir(dir, dry_run: false, verbose: false, exts: nil, exclude: nil) ⇒ Object

扫描并处理目录。

参数:

dir       - 目录路径
dry_run   - true 时仅检测不修改
verbose   - true 时输出详细日志
exts      - 自定义扩展名数组(nil 用 DEFAULT_EXTS)
exclude   - 排除的目录名数组(如 ["node_modules", ".git"])

返回: [Result, ...]



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/elect/processor.rb', line 94

def self.process_dir(dir, dry_run: false, verbose: false, exts: nil, exclude: nil)
  d = Pathname.new(dir)
  exts = (exts || DEFAULT_EXTS).map { |e| e.start_with?(".") ? e : ".#{e}" }
  exclude_set = (exclude || %w[node_modules .git .svn __pycache__ dist build]).to_set

  results = []
  d.find do |path|
    next if path == d
    if path.directory?
      next if exclude_set.include?(path.basename.to_s)
      next
    end

    next unless exts.include?(path.extname.downcase)

    r = process_file(path, dry_run: dry_run, verbose: verbose)
    results << r
  end

  results
end

.process_file(path, dry_run: false, verbose: false) ⇒ Object

扫描并处理单个文件。

参数:

path      - 文件路径(String 或 Pathname)
dry_run   - true 时仅检测不改写文件
verbose   - true 时输出详细日志

返回: Result



39
40
41
42
43
44
45
46
47
48
49
50
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
# File 'lib/elect/processor.rb', line 39

def self.process_file(path, dry_run: false, verbose: false)
  p = Pathname.new(path)
  result = Result.new(path: p.to_s, removed: 0, status: :skip)

  unless p.file?
    result.status = :not_found
    return result
  end

  # 统一走二进制读取 + 编码强制转换,避免非 UTF-8 文件触发 ArgumentError
  raw = begin
    data = File.binread(p.to_s)
    data = data.force_encoding(Encoding::UTF_8)
    unless data.valid_encoding?
      data = data.encode(Encoding::UTF_8, invalid: :replace, undef: :replace, replace: "?")
    end
    data
  rescue => e
    warn "[elect] 跳过 #{p}: #{e.message}" if verbose
    result.status = :error
    return result
  end

  n = Cleaner.detect(raw)
  if n.zero?
    result.status = :clean
    return result
  end

  if dry_run
    result.removed = n
    result.status = :found
    puts "  [DRY] #{p} — 发现 #{n} 处水印"
    return result
  end

  cleaned, removed = Cleaner.clean(raw)
  p.write(cleaned, encoding: "utf-8")
  result.removed = removed
  result.status = :cleaned
  puts "  [OK]  #{p} — 移除 #{removed} 处水印" if verbose
  result
end

.report(results) ⇒ Object

打印汇总报告



118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/elect/processor.rb', line 118

def self.report(results)
  total      = results.size
  found      = results.count { |r| r.status == :found }
  cleaned    = results.count { |r| r.status == :cleaned }
  clean      = results.count { |r| r.status == :clean }
  skipped    = results.count { |r| r.status == :skip }
  errors     = results.count { |r| r.status == :error }
  total_rm   = results.sum { |r| r.removed }

  puts
  puts "=" * 50
  puts "  扫描完毕"
  puts "=" * 50
  puts "  扫描文件 : #{total}"
  puts "  发现水印 : #{found + cleaned} 个文件"
  puts "  已清理   : #{cleaned} 个文件 (共移除 #{total_rm} 处水印)"
  puts "  无水印   : #{clean} 个文件"
  puts "  跳过     : #{skipped}"
  puts "  错误     : #{errors}" if errors.positive?
  puts "=" * 50
end