cc 1.1.4 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (5) hide show
  1. checksums.yaml +4 -4
  2. data/cc.rb +1 -0
  3. data/enum.rb +141 -0
  4. data/shell-tools.rb +264 -0
  5. metadata +2 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c35c12b969222418912303a9bd84312b4b3e3a93823b1bee849ccd085b6e98ba
4
- data.tar.gz: 73b5414aba0e02166ed99390133872382ed96d7efd1cd08f63abce2cd4726e69
3
+ metadata.gz: 9d516f93659f22c9c1cc96949b6b28a18f9b0a4488df88d0534b93e02d384ec1
4
+ data.tar.gz: cacf6949dfacd5676274f8189eb6f103ab10bbd8449e97d5ed719647c39fbb83
5
5
  SHA512:
6
- metadata.gz: 8488d76dd5383695efc48e55afc03ea20634312e0be1a98597468c47f28f48b25afe748e6c3029ac5a21fd37824571d8ed2e9d188994e66dc3ea65ee665ce5f4
7
- data.tar.gz: 4f5f1c3ea756d171ccdbaf97c43d96f189cfe531f351eee9a74f7e3850a6d4d0cfa4754f2656ccc0943ae85d2d2442dbf1e36c1f1907e8734a2f1f6d598af073
6
+ metadata.gz: 439bf5ca21f7ebc3ae75e9f15864e739554aed7d1020a686a1890bf75defcf7e2ce338ae9f47266eda782c8cb8589ae79b9c9581aa0bef7b9bebdebb3305a0d6
7
+ data.tar.gz: 82b49a5413e171490cb09f9ba0057c5efa39642c7c4814b1463fd90b272225d52e547bb23b87188797358f42f14d92a5d953aa11af6acf9e6141f816fde196ea
data/cc.rb CHANGED
@@ -10,6 +10,7 @@ $modlist = [
10
10
  'file',
11
11
  'kernel',
12
12
  'monkey-patch',
13
+ 'shell-tools',
13
14
  'number',
14
15
  'regexp',
15
16
  'string',
data/enum.rb CHANGED
@@ -14,6 +14,51 @@
14
14
  puts "Enumberable objects could be added head or tail:"
15
15
  pp [ 1 , [2], 3 ].unfold_head( :a, :b, :c )
16
16
  pp [[1], 2 , [3]].unfold_tail(*[:x, :y, :z])
17
+
18
+ puts "Hash could project and serialize on a subscope as a sub hash or array:"
19
+ {a: 1 ,b: 2,c: 3}.project(:a, :c) # => {:a=>1, :c=>3}
20
+ {a: 1 ,b: 2,c: 3}.serialize(:a, :c) # => [1, 3]
21
+
22
+ puts "Array could mapping with a subscope as a key-val array:"
23
+ a = [[1,2,3], [4,5,6], [7,8]]
24
+ a.mapping [:a, :b, :c] # => [{:a=>1, :b=>2, :c=>3}, {:a=>4, :b=>5, :c=>6}, {:a=>7, :b=>8, :c=>nil}]
25
+ a.mapping [:a, :d] # => [{:a=>1, :d=>2}, {:a=>4, :d=>5}, {:a=>7, :d=>8}]
26
+
27
+ puts "Building a RangeTree to query a range of records:"
28
+ pp(rt = RangeTree.new(records = [
29
+ [[1, 3], :a],
30
+ [[2, 4], :b],
31
+ [[2, 7], :c],
32
+ [[6], :d],
33
+ [[4, 5], :e],
34
+ [[8], :f],
35
+ [[10], :g],
36
+ :y,
37
+ :z
38
+ ]))
39
+ # {1=>{3=>[:a]},
40
+ # 2=>{4=>[:b], 7=>[:c]},
41
+ # 6=>{6=>[:d]},
42
+ # 4=>{5=>[:e]},
43
+ # 8=>{8=>[:f]},
44
+ # 10=>{10=>[:g]},
45
+ # 0=>{0=>[:y, :z]}}
46
+
47
+ pp rt.query( Range.new(1,2) )
48
+ # ["complete", {[1, 3]=>[:a]}]
49
+
50
+ pp rt.query( [4,7] )
51
+ # ["complete", {[2, 7]=>[:c]}]
52
+
53
+ pp rt.query( 6 )
54
+ # ["complete", {[2, 7]=>[:c], [6, 6]=>[:d]}]
55
+
56
+ pp rt.query( [1,6] )
57
+ # ["partial",
58
+ # {[1, 3]=>[:a], [2, 4]=>[:b], [2, 7]=>[:c], [6, 6]=>[:d], [4, 5]=>[:e]}]
59
+
60
+ pp rt.query( :a )
61
+ # ["unformal", {[0, 0]=>[]}]
17
62
  =end
18
63
 
19
64
  module Enumerable
@@ -75,3 +120,99 @@ class Array
75
120
  return new_records
76
121
  end
77
122
  end
123
+
124
+ class RangeTree < Hash
125
+ attr_reader :a
126
+
127
+ # Records := [ [Range|Point, Record] | Record, ... ]
128
+ def initialize records
129
+ merge records
130
+ end
131
+
132
+ def merge records
133
+ records.each do|record|
134
+ head, rest = record
135
+ if head.is_a?(Range)
136
+ starter, finisher = head.min, head.max
137
+ elsif head.is_a?(Array)
138
+ starter, finisher = head.sort.first, head.sort.last
139
+ elsif head.is_a?(Numeric)
140
+ starter, finisher = head, head
141
+ else
142
+ starter, finisher, rest = 0, 0, record
143
+ end
144
+ self[starter] ||= {}
145
+ self[starter][finisher] ||= []
146
+ self[starter][finisher] << rest
147
+ self[starter][finisher].uniq!
148
+ end
149
+ @start_keys = self.keys.sort
150
+ end
151
+
152
+ def update_key
153
+ @start_keys = self.keys.sort
154
+ end
155
+
156
+ def unikey target
157
+ if target.is_a?(Range)
158
+ skey, fkey = target.min, target.max
159
+ elsif target.is_a?(Array)
160
+ skey, fkey = target.sort.first, target.sort.last
161
+ elsif target.is_a?(Numeric)
162
+ skey, fkey = target, target
163
+ else
164
+ skey, fkey = 0, 0
165
+ end
166
+ return skey, fkey
167
+ end
168
+
169
+ def locate target
170
+ skey, fkey = unikey(target)
171
+ keys = []
172
+ start_keys = self.keys.sort
173
+ candi_keys = start_keys.select{|sk|sk<=skey}
174
+ candi_keys.each do|candi_key|
175
+ finish_keys = self[candi_key].keys.sort
176
+ cand_keys = finish_keys.select{|fk|fk>=fkey}.map{|cand_key|[candi_key, cand_key]}
177
+ keys += cand_keys
178
+ end
179
+ return keys
180
+ end
181
+
182
+ def search target
183
+ keys = []
184
+ skey, fkey = unikey(target)
185
+ self.each do|sk, candis|
186
+ candis.each do|fk, cands|
187
+ next if fkey < sk || fk < skey
188
+ keys << [sk,fk]
189
+ end
190
+ end
191
+ return keys
192
+ end
193
+
194
+ def index target
195
+ keys = locate(target)
196
+ if keys.empty?
197
+ return 'partial', search(target)
198
+ elsif keys==[[0,0]]
199
+ return 'unformal', [[0,0]]
200
+ else
201
+ return 'complete', keys
202
+ end
203
+ end
204
+
205
+ def query target
206
+ result = {}
207
+ state, keys = index(target)
208
+ keys.each do|keyp|
209
+ sk, fk = keyp
210
+ result[keyp] = self[sk][fk]
211
+ end
212
+ if state=='unformal'
213
+ self[0] ||= {}
214
+ result[[0,0]] = (self[0][0]||[]).include?(target) ? target : []
215
+ end
216
+ return state, result
217
+ end
218
+ end
data/shell-tools.rb ADDED
@@ -0,0 +1,264 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+
4
+ require 'io/console'
5
+
6
+ class ProgressBar
7
+ # 预设主题
8
+ THEMES = {
9
+ classic: { fill: '█', empty: '░', left: '[', right: ']', arrow: '>' },
10
+ modern: { fill: '●', empty: '○', left: '', right: '', arrow: '▶' },
11
+ blocks: { fill: '■', empty: '□', left: '│', right: '│', arrow: '▶' },
12
+ dots: { fill: '◉', empty: '◎', left: '⟨', right: '⟩', arrow: '→' },
13
+ minimal: { fill: '=', empty: '-', left: '[', right: ']', arrow: '>' },
14
+ hearts: { fill: '♥', empty: '♡', left: ' ', right: ' ', arrow: '💕' }
15
+ }
16
+
17
+ attr_reader :total, :current, :start_time
18
+
19
+ def initialize(total, title: "Processing", theme: :modern, width: 40, show_percentage: true, show_eta: true, color: true)
20
+ @total = total
21
+ @current = 0
22
+ @title = title
23
+ @theme = THEMES[theme] || THEMES[:modern]
24
+ @width = width
25
+ @show_percentage = show_percentage
26
+ @show_eta = show_eta
27
+ @color = color
28
+ @start_time = Time.now
29
+ @last_update = 0
30
+ @mutex = Mutex.new
31
+
32
+ # ANSI 颜色代码
33
+ @colors = {
34
+ reset: "\e[0m",
35
+ bold: "\e[1m",
36
+ green: "\e[32m",
37
+ yellow: "\e[33m",
38
+ blue: "\e[34m",
39
+ magenta: "\e[35m",
40
+ cyan: "\e[36m",
41
+ gray: "\e[90m"
42
+ }
43
+
44
+ # 隐藏光标
45
+ print "\e[?25l"
46
+ end
47
+
48
+ # 更新进度
49
+ def update(step = 1)
50
+ @mutex.synchronize do
51
+ @current += step
52
+ @current = @total if @current > @total
53
+ refresh if should_refresh?
54
+ end
55
+ end
56
+
57
+ # 直接设置进度
58
+ def set(value)
59
+ @mutex.synchronize do
60
+ @current = [[value, @total].min, 0].max
61
+ refresh
62
+ end
63
+ end
64
+
65
+ # 完成进度条
66
+ def finish(message: "Done!")
67
+ @mutex.synchronize do
68
+ @current = @total
69
+ refresh
70
+ puts # 换行
71
+ show_cursor
72
+ puts colorize(message, :green) unless message.empty?
73
+ end
74
+ end
75
+
76
+ # 显示统计信息
77
+ def stats
78
+ elapsed = Time.now - @start_time
79
+ rate = @current / elapsed rescue 0
80
+ {
81
+ total: @total,
82
+ current: @current,
83
+ percentage: (@current.to_f / @total * 100).round(1),
84
+ elapsed: format_time(elapsed),
85
+ eta: format_time(eta),
86
+ rate: rate.round(2)
87
+ }
88
+ end
89
+
90
+ # 清理资源
91
+ def dispose
92
+ show_cursor
93
+ end
94
+
95
+ private
96
+
97
+ def should_refresh?
98
+ now = Time.now.to_f
99
+ return false if now - @last_update < 0.05 # 限制刷新率 20fps
100
+ @last_update = now
101
+ true
102
+ end
103
+
104
+ def refresh
105
+ percentage = @current.to_f / @total
106
+ filled = (percentage * @width).round
107
+ empty = @width - filled
108
+
109
+ bar = @theme[:fill] * filled +
110
+ (@current < @total ? @theme[:arrow] : @theme[:fill]) +
111
+ @theme[:empty] * [empty - 1, 0].max
112
+
113
+ # 构建输出字符串
114
+ parts = []
115
+
116
+ # 标题
117
+ parts << colorize(sprintf("%-15s", @title), :bold)
118
+
119
+ # 进度条
120
+ bar_color = percentage >= 1.0 ? :green : (percentage > 0.5 ? :cyan : :yellow)
121
+ parts << "#{@theme[:left]}#{colorize(bar, bar_color)}#{@theme[:right]}"
122
+
123
+ # 百分比
124
+ if @show_percentage
125
+ parts << colorize(sprintf("%6.1f%%", percentage * 100), :magenta)
126
+ end
127
+
128
+ # 计数
129
+ parts << colorize("[#{@current}/#{@total}]", :gray)
130
+
131
+ # ETA
132
+ if @show_eta && @current > 0 && @current < @total
133
+ parts << colorize("ETA: #{format_time(eta)}", :blue)
134
+ end
135
+
136
+ # 清除行并输出
137
+ print "\r\e[K" + parts.join(' ')
138
+ $stdout.flush
139
+ end
140
+
141
+ def eta
142
+ return 0 if @current == 0
143
+ elapsed = Time.now - @start_time
144
+ remaining = @total - @current
145
+ (elapsed / @current) * remaining
146
+ end
147
+
148
+ def format_time(seconds)
149
+ return "0s" if seconds < 1
150
+ if seconds < 60
151
+ "#{seconds.round}s"
152
+ elsif seconds < 3600
153
+ "#{(seconds / 60).floor}m #{(seconds % 60).round}s"
154
+ else
155
+ "#{(seconds / 3600).floor}h #{((seconds % 3600) / 60).floor}m"
156
+ end
157
+ end
158
+
159
+ def colorize(text, color)
160
+ return text unless @color
161
+ "#{@colors[color]}#{text}#{@colors[:reset]}"
162
+ end
163
+
164
+ def show_cursor
165
+ print "\e[?25h"
166
+ end
167
+ end
168
+
169
+ # 辅助方法(用于示例中的颜色输出)
170
+ def colorize(text, color)
171
+ colors = { green: "\e[32m", yellow: "\e[33m", gray: "\e[90m", reset: "\e[0m" }
172
+ "#{colors[color]}#{text}#{colors[:reset]}"
173
+ end
174
+
175
+ =begin
176
+ # ==================== 使用示例 ====================
177
+ puts "🚀 Ruby Fancy Progress Bar Demo"
178
+ puts "=" * 50
179
+
180
+ # 示例 1: 基础用法
181
+ puts "\n📊 示例 1: 基础文件处理"
182
+ bar = ProgressBar.new(100, title: "Downloading", theme: :modern)
183
+ 100.times do |i|
184
+ sleep(0.03) # 模拟工作
185
+ bar.update
186
+ end
187
+ bar.finish(message: "✅ 下载完成!")
188
+
189
+ # 示例 2: 不同主题展示
190
+ puts "\n🎨 示例 2: 主题展示"
191
+ [:classic, :blocks, :dots, :minimal].each do |theme_name|
192
+ bar = ProgressBar.new(50, title: theme_name.to_s, theme: theme_name, width: 30)
193
+ 50.times do
194
+ sleep(0.02)
195
+ bar.update
196
+ end
197
+ bar.finish(message: "")
198
+ end
199
+
200
+ # 示例 3: 批量任务处理(带错误处理)
201
+ puts "\n📁 示例 3: 批量文件处理"
202
+ files = (1..20).map { |n| "file_#{n}.txt" }
203
+ bar = ProgressBar.new(files.size, title: "Processing", theme: :hearts, color: true)
204
+ processed = []
205
+ files.each do |file|
206
+ sleep(0.1) # 模拟处理时间
207
+ processed << file
208
+ bar.update
209
+ # 模拟偶尔的错误
210
+ if rand < 0.1
211
+ print "\n⚠️ #{colorize("警告: #{file} 处理异常", :yellow)}"
212
+ end
213
+ end
214
+ bar.finish(message: "✨ 处理了 #{processed.size} 个文件")
215
+
216
+ # 示例 4: 嵌套进度条(多阶段任务)
217
+ puts "\n🏗️ 示例 4: 多阶段构建任务"
218
+ phases = [
219
+ { name: "Compiling", items: 30 },
220
+ { name: "Testing", items: 20 },
221
+ { name: "Packaging", items: 15 }
222
+ ]
223
+ phases.each do |phase|
224
+ puts "\n阶段: #{phase[:name]}"
225
+ bar = ProgressBar.new(phase[:items], title: phase[:name], theme: :modern)
226
+ phase[:items].times do
227
+ sleep(0.05)
228
+ bar.update
229
+ end
230
+ bar.finish(message: "")
231
+ end
232
+ puts colorize("🎉 所有阶段完成!", :green)
233
+
234
+ # 示例 5: 实时速度显示(大数据处理)
235
+ puts "\n⚡ 示例 5: 大数据处理(带实时统计)"
236
+ total_items = 1000
237
+ bar = ProgressBar.new(total_items, title: "BigData", theme: :blocks, width: 50)
238
+ total_items.times do |i|
239
+ sleep(0.01) # 模拟快速处理
240
+ # 每 100 个显示一次统计
241
+ if i % 100 == 0 && i > 0
242
+ s = bar.stats
243
+ print "\n #{colorize("速度: #{s[:rate]} items/s | 已用: #{s[:elapsed]} | 剩余: #{s[:eta]}", :gray)}"
244
+ end
245
+ bar.update
246
+ end
247
+ bar.finish
248
+
249
+ # 示例 6: 手动控制进度(非均匀任务)
250
+ puts "\n🎮 示例 6: 手动进度控制(非均匀任务)"
251
+ bar = ProgressBar.new(100, title: "Uploading", theme: :dots)
252
+ # 模拟不同大小的文件上传
253
+ uploads = [10, 25, 5, 30, 20, 10]
254
+ uploads.each_with_index do |size, idx|
255
+ sleep(0.3) # 模拟上传时间
256
+ bar.set(bar.current + size)
257
+ print "\n 上传了 chunk_#{idx + 1}.bin (#{size}MB)"
258
+ end
259
+ bar.finish(message: "上传完成")
260
+ # 确保光标显示
261
+ print "\e[?25h"
262
+ puts "\n" + "=" * 50
263
+ puts "✨ 所有演示完成! 你可以复制 ProgressBar 类到你的项目中使用。"
264
+ =end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cc
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.4
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt
@@ -32,6 +32,7 @@ files:
32
32
  - monkey-patch.rb
33
33
  - number.rb
34
34
  - regexp.rb
35
+ - shell-tools.rb
35
36
  - string.rb
36
37
  - tree.rb
37
38
  homepage: https://github.com/ChenMeng1365/custom-core