cc 1.2.1 → 1.4.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 (9) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +29 -3
  3. data/cc.rb +1 -0
  4. data/monkey-patch.rb +375 -1
  5. data/text-client.rb +297 -0
  6. data/text-server.rb +403 -0
  7. data/text-tools.rb +418 -0
  8. data/tree.rb +184 -184
  9. metadata +5 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4fc0484d6d2387f8043520b7981b52be8968f1a233cf5e110395a2dcc9ab5fa8
4
- data.tar.gz: 88f19e9a08e517ccdebb8d9f5d8dbb8afec0dd675d6b0c6df057c40703d75993
3
+ metadata.gz: 560df541d3d489827cf9873d8ad9b78efb20e454824728462dff70fd955b477a
4
+ data.tar.gz: 235e3d4bc81f79b5bc3eb72303ef4df9ae1f724753a7484f451fff75b9f7bb53
5
5
  SHA512:
6
- metadata.gz: 371bdf3d14c78623c029bd58aff0002383f256dc9346ab5f6586b0ad7920690c9698338d1d73ccbffcab07019d0c9a132ced0365d6f7198c3c7040371329900e
7
- data.tar.gz: 874c41883cb25ddf44790b37d8b7589ef5ff87bb07e25d5d7908f2553dedb3b9cc96af751a7886902839e3e7084931cdd1a30b547c8c6c43a63721bf0b4af6b8
6
+ metadata.gz: 90a657521953f6e3a9b69b7aef92f41f2f10c5e87faa858717df4f6551cf06e7a83d16836c2fb5aab053254b48be0281908707ea6073acdc03e3c5de7b42f858
7
+ data.tar.gz: 2c250b3c62437a27116357cc331947cac3532691f2dcbb116d7814ff1c8e5fb9f585301498933e84f711471a1f8e34b6f9528b8448682622ce32903fded145cf
data/README.md CHANGED
@@ -1,3 +1,29 @@
1
- # custom-core
2
-
3
- CC
1
+ # custom-core
2
+
3
+ CC
4
+
5
+ ## textmind(text-tools / text-server / text-client)
6
+
7
+ 移植自 imdoc/TextUtils 的文本直觉操作族,v1.4.0 起随 cc 自带,三个文件各司其职:
8
+
9
+ - **text-tools.rb** —— 操作库本体:`TextAbstract` 模块函数(draw_fragments / match_paragraph /
10
+ match_cascade / match_html_tag)+ String/Array/Hash 的直觉操作扩展
11
+ (`head?` `tail?` `matches` `cut` `-` `/` `exchange` `catch` `match` `sub` `get` `set` `+` …)。
12
+ 加载方式:`require 'cc'; CC.use 'text-tools'`
13
+
14
+ - **text-server.rb** —— **S 端**:命令行启动解析服务(原 config.ru 的改造版)。
15
+ `ruby text-server.rb [--port 9292] [--host 0.0.0.0]`,
16
+ 40 个 POST 端点(/type/* /text/* /list/* /tree/*),路由与参数名和原服务一致,
17
+ 原 Postman 集合可继续使用;CORS 由 rack-cors 依赖改为手工响应头。
18
+
19
+ - **text-client.rb** —— **C 端**:命令行传入解析。
20
+ `ruby text-client.rb <ns> <op> [参数...]`,默认本地执行(不依赖服务),
21
+ `--remote URL` 时改走 S 端,本地/远程结果一致;数据走 `--text/--list/--tree` 或管道 stdin。
22
+
23
+ ```shell
24
+ ruby text-client.rb type int --radix 2 --text 100 # => 4
25
+ echo "abedef" | ruby text-client.rb text exchange --oldtext e --newtext z
26
+ ruby text-client.rb list map --func "proc{|c| c * 2}" --list '[1,2,3]'
27
+ ```
28
+
29
+ 测试:`ruby -I . tests/text_tools_test.rb`(另有 text_server_test / text_client_test)
data/cc.rb CHANGED
@@ -14,6 +14,7 @@ $modlist = [
14
14
  'number',
15
15
  'regexp',
16
16
  'string',
17
+ 'text-tools',
17
18
  'tree',
18
19
  'trace',
19
20
  'logic'
data/monkey-patch.rb CHANGED
@@ -4,7 +4,7 @@
4
4
  # HOW TO USE #
5
5
  ############################################################################################################
6
6
 
7
- =begin
7
+ =begin # 旧版
8
8
  require 'cc'
9
9
  CC.use 'monkey-patch'
10
10
 
@@ -50,6 +50,380 @@
50
50
  p a.compize(Object), a.mod1, a.mod2, a.mod1_20110101
51
51
  =end
52
52
 
53
+ =begin # 新版
54
+ puts "=" * 60
55
+ puts "模块级方法版本控制系统 v4 演示"
56
+ puts "=" * 60
57
+
58
+ # ========================================
59
+ # 定义版本化模块
60
+ # ========================================
61
+ module Calculator
62
+ include MonkeyPatch
63
+
64
+ # 方式1: 传统 block
65
+ ADD_V1 = defv(:add) { |a, b| a + b }
66
+ puts "[方式1] 定义 add v1, 签名: #{ADD_V1}"
67
+
68
+ ADD_V2 = defv(:add) { |a, b|
69
+ result = a + b
70
+ puts "[v2] 计算 #{a} + #{b} = #{result}"
71
+ result
72
+ }
73
+ puts "[方式1] 定义 add v2, 签名: #{ADD_V2}"
74
+ end
75
+
76
+ # 方式2: 从外部数组批量生成
77
+ EXTERNAL_SPECS = [
78
+ [:greet, "World", proc { |name| "Hello, #{name}!" }],
79
+ [:multiply, 1, proc { |a, b| a * b }],
80
+ ]
81
+
82
+ module GreetingService
83
+ include MonkeyPatch
84
+
85
+ EXTERNAL_SPECS.each do |spec|
86
+ name, default, body = spec
87
+ sig = defv(name, default, body)
88
+ puts "[方式2] 定义 #{name}, 默认=#{default.inspect}, 签名: #{sig}"
89
+ end
90
+ end
91
+
92
+ # ========================================
93
+ # 测试 module_function 效果
94
+ # ========================================
95
+ puts "\n" + "-" * 50
96
+ puts "测试 module_function 效果(v4 核心特性)"
97
+ puts "-" * 50
98
+
99
+ # 实例调用
100
+ obj = Object.new.extend(Calculator)
101
+ puts "obj.add(2, 3) = #{obj.add(2, 3)}"
102
+
103
+ # 模块方法调用(module_function 效果)
104
+ puts "Calculator.add(10, 20) = #{Calculator.add(10, 20)}"
105
+ puts "Calculator.send(:add, 5, 7) = #{Calculator.send(:add, 5, 7)}"
106
+
107
+ # 模块方法也走版本控制
108
+ puts "\n--- 模块方法版本切换 ---"
109
+ puts "当前默认: Calculator.add(1, 1) = #{Calculator.add(1, 1)}"
110
+
111
+ Calculator.rollback_to(:add, Calculator::ADD_V1)
112
+ puts "回滚到 v1: Calculator.add(1, 1) = #{Calculator.add(1, 1)}"
113
+
114
+ Calculator.rollback_to(:add, Calculator::ADD_V2)
115
+ puts "恢复 v2: Calculator.add(1, 1) = #{Calculator.add(1, 1)}"
116
+
117
+ # 实例调用同步受影响(共享版本库)
118
+ puts "obj.add(1, 1) = #{obj.add(1, 1)} (与模块方法同步)"
119
+
120
+ # ========================================
121
+ # 测试 GreetingService
122
+ # ========================================
123
+ puts "\n" + "-" * 50
124
+ puts "测试 GreetingService(方式2 + module_function)"
125
+ puts "-" * 50
126
+
127
+ puts "GreetingService.greet = #{GreetingService.greet}"
128
+ puts 'GreetingService.greet("Alice") = ' + GreetingService.greet("Alice").to_s
129
+ puts "GreetingService.multiply(3, 4) = #{GreetingService.multiply(3, 4)}"
130
+
131
+ # 实例调用
132
+ g = Object.new.extend(GreetingService)
133
+ puts "g.greet = #{g.greet}"
134
+ puts 'g.greet("Bob") = ' + g.greet("Bob").to_s
135
+
136
+ # ========================================
137
+ # 版本历史
138
+ # ========================================
139
+ puts "\n" + "-" * 50
140
+ puts "版本历史"
141
+ puts "-" * 50
142
+
143
+ Calculator.version_history(:add).each do |v|
144
+ puts " Calculator.add: #{v[:signature]} @ #{v[:timestamp]}"
145
+ end
146
+
147
+ GreetingService.version_history(:greet).each do |v|
148
+ puts " GreetingService.greet: #{v[:signature]} @ #{v[:timestamp]}"
149
+ end
150
+
151
+ # ========================================
152
+ # 跨模块隔离
153
+ # ========================================
154
+ puts "\n" + "=" * 60
155
+ puts "跨模块隔离测试"
156
+ puts "=" * 60
157
+ puts "Calculator 版本库: #{Calculator.versioned_methods.inspect}"
158
+ puts "GreetingService 版本库: #{GreetingService.versioned_methods.inspect}"
159
+
160
+ # ========================================
161
+ # 全局注册表
162
+ # ========================================
163
+ puts "\n" + "=" * 60
164
+ puts "全局注册表结构"
165
+ puts "=" * 60
166
+ MonkeyPatch::VERSION_REGISTRY.each do |mod, methods|
167
+ puts "模块: #{mod}"
168
+ methods.each do |name, versions|
169
+ puts " 方法: #{name}"
170
+ versions.each do |sig, vm|
171
+ next if sig == :__latest__
172
+ puts " [#{sig}] => #{vm}"
173
+ end
174
+ puts " [LATEST] => #{versions[:__latest__]}"
175
+ end
176
+ end
177
+ =end
178
+
179
+
180
+ # ============================================================
181
+ # 新版本MonkeyPatch
182
+ # 模块级方法版本控制系统 (Module Method Versioning) - v4
183
+ # ============================================================
184
+ # 特性:
185
+ # 1. 模块作为方法仓库,每个方法名对应一个版本链
186
+ # 2. 支持按签名回溯历史版本
187
+ # 3. 不传签名时默认调取最新版本
188
+ # 4. 模块间版本隔离,互不干扰
189
+ # 5. 支持两种调用方式:
190
+ # - 传统 block: defv(:name) { |a| ... }
191
+ # - 数组重构: defv(:name, default_param, proc)
192
+ # 6. module_function 支持:模块方法也走版本控制
193
+ # - obj.a 和 A.a 共享同一个版本库
194
+ # ============================================================
195
+
196
+ module MonkeyPatch
197
+ VERSION_REGISTRY = {}
198
+ SIGNATURE_COUNTER = Hash.new(0)
199
+
200
+ class VersionedMethod
201
+ attr_reader :name, :signature, :body, :timestamp, :module_ref
202
+
203
+ def initialize(name:, signature:, body:, module_ref:)
204
+ @name = name
205
+ @signature = signature
206
+ @body = body
207
+ @timestamp = Time.now
208
+ @module_ref = module_ref
209
+ end
210
+
211
+ def call(*args)
212
+ outer_block = block_given? ? Proc.new : nil
213
+ if outer_block
214
+ @module_ref.instance_exec(*args, outer_block, &@body)
215
+ else
216
+ @module_ref.instance_exec(*args, &@body)
217
+ end
218
+ end
219
+
220
+ def to_s
221
+ "#<VersionedMethod #{@module_ref}##{@name}@#{@signature} #{@timestamp}>"
222
+ end
223
+ alias inspect to_s
224
+ end
225
+
226
+ def self.included(base)
227
+ base.extend(ClassMethods)
228
+ end
229
+
230
+ # ----------------------------------------------------------
231
+ # 类方法接口
232
+ # ----------------------------------------------------------
233
+ module ClassMethods
234
+ def define_versioned_method(name, *args, signature: nil, &block)
235
+ if block_given?
236
+ _register_version(name, signature: signature, body: block)
237
+ elsif args.size >= 2 && args[1].is_a?(Proc)
238
+ default_param = args[0]
239
+ body_proc = args[1]
240
+
241
+ wrapped = proc { |*call_args|
242
+ if call_args.empty?
243
+ body_proc.call(default_param)
244
+ else
245
+ body_proc.call(*call_args)
246
+ end
247
+ }
248
+ _register_version(name, signature: signature, body: wrapped)
249
+ else
250
+ raise ArgumentError, "必须提供方法块,或传入 (name, default_param, proc)"
251
+ end
252
+ end
253
+
254
+ def defv(name, *args, &block)
255
+ if block_given?
256
+ define_versioned_method(name, *args, &block)
257
+ elsif args.size >= 1 && args[-1].is_a?(Proc)
258
+ if args.size >= 2 && args[0].is_a?(String) && args[1].is_a?(Proc)
259
+ define_versioned_method(name, *args)
260
+ elsif args.size == 1
261
+ define_versioned_method(name, nil, args[0])
262
+ else
263
+ define_versioned_method(name, *args)
264
+ end
265
+ else
266
+ raise ArgumentError, "defv 需要 block 或 (default_param, proc)"
267
+ end
268
+ end
269
+
270
+ def get_versioned_method(name, signature = nil)
271
+ versions = _method_versions[name]
272
+ return nil unless versions
273
+
274
+ sig = signature || versions[:__latest__]
275
+ return nil unless sig
276
+
277
+ versions[sig]
278
+ end
279
+
280
+ def call_versioned(name, signature = nil, *args, &block)
281
+ vm = get_versioned_method(name, signature)
282
+ raise NameError, "方法 `#{name}` 版本 `#{signature || 'latest'}` 不存在" unless vm
283
+
284
+ vm.call(*args, &block)
285
+ end
286
+
287
+ def method_versions(name)
288
+ versions = _method_versions[name] || {}
289
+ versions.reject { |k, _| k == :__latest__ }.transform_values(&:to_s)
290
+ end
291
+
292
+ def versioned_methods
293
+ _method_versions.keys
294
+ end
295
+
296
+ def version_history(name)
297
+ return [] unless _method_versions[name]
298
+
299
+ _method_versions[name]
300
+ .reject { |k, _| k == :__latest__ }
301
+ .map { |sig, vm| { signature: sig, timestamp: vm.timestamp, method: vm } }
302
+ .sort_by { |h| h[:timestamp] }
303
+ end
304
+
305
+ def rollback_to(name, signature)
306
+ versions = _method_versions[name]
307
+ raise NameError, "方法 `#{name}` 不存在" unless versions
308
+ raise KeyError, "签名 `#{signature}` 不存在" unless versions[signature]
309
+
310
+ versions[:__latest__] = signature
311
+ signature
312
+ end
313
+
314
+ def remove_version(name, signature)
315
+ versions = _method_versions[name]
316
+ return false unless versions&.key?(signature)
317
+
318
+ if versions.reject { |k, _| k == :__latest__ }.size <= 1
319
+ raise "不能删除方法 `#{name}` 的唯一版本"
320
+ end
321
+
322
+ versions.delete(signature)
323
+
324
+ if versions[:__latest__] == signature
325
+ latest = versions.reject { |k, _| k == :__latest__ }.keys.last
326
+ versions[:__latest__] = latest
327
+ end
328
+
329
+ true
330
+ end
331
+
332
+ def clear_versions(name)
333
+ _method_versions.delete(name)
334
+ if method_defined?(name)
335
+ remove_method(name)
336
+ end
337
+ if singleton_class.method_defined?(name)
338
+ singleton_class.remove_method(name)
339
+ end
340
+ end
341
+
342
+ private
343
+
344
+ def _register_version(name, signature: nil, body:)
345
+ sig = signature || _generate_signature(name)
346
+
347
+ if _method_versions[name]&.key?(sig)
348
+ raise ArgumentError, "方法 `#{name}` 的签名 `#{sig}` 已存在"
349
+ end
350
+
351
+ versioned = VersionedMethod.new(
352
+ name: name,
353
+ signature: sig,
354
+ body: body,
355
+ module_ref: self
356
+ )
357
+
358
+ _method_versions[name] ||= {}
359
+ _method_versions[name][sig] = versioned
360
+ _method_versions[name][:__latest__] = sig
361
+
362
+ # 安装实例方法调度器(首次定义时)
363
+ unless method_defined?(name) || private_method_defined?(name)
364
+ _install_instance_dispatcher(name)
365
+ end
366
+
367
+ # 安装模块方法调度器(首次定义时)
368
+ unless singleton_class.method_defined?(name)
369
+ _install_module_dispatcher(name)
370
+ end
371
+
372
+ sig
373
+ end
374
+
375
+ def _generate_signature(name)
376
+ SIGNATURE_COUNTER[name] += 1
377
+ "#{name}_v#{SIGNATURE_COUNTER[name]}_#{Time.now.to_i}"
378
+ end
379
+
380
+ def _method_versions
381
+ VERSION_REGISTRY[self] ||= {}
382
+ end
383
+
384
+ # 实例方法调度器:obj.a 调用时路由到最新版本
385
+ def _install_instance_dispatcher(name)
386
+ define_method(name) do |*args, &block|
387
+ mod = self.class.ancestors.find { |m| m.respond_to?(:get_versioned_method) }
388
+ mod ||= self.singleton_class.ancestors.find { |m| m.respond_to?(:get_versioned_method) }
389
+
390
+ versions = MonkeyPatch::VERSION_REGISTRY[mod]&.[](name)
391
+ unless versions
392
+ raise NoMethodError, "未找到版本化方法 `#{name}`"
393
+ end
394
+
395
+ latest_sig = versions[:__latest__]
396
+ latest = versions[latest_sig]
397
+
398
+ unless latest
399
+ raise NoMethodError, "方法 `#{name}` 没有可用版本"
400
+ end
401
+
402
+ latest.call(*args, &block)
403
+ end
404
+ end
405
+
406
+ # 模块方法调度器:A.a 调用时路由到最新版本
407
+ def _install_module_dispatcher(name)
408
+ singleton_class.send(:define_method, name) do |*args, &block|
409
+ # 模块方法直接在当前模块上调用 call_versioned
410
+ call_versioned(name, nil, *args, &block)
411
+ end
412
+ end
413
+ end
414
+
415
+ # 实例方法接口
416
+ def call_version(name, signature = nil, *args, &block)
417
+ mod = self.class.ancestors.find { |m| m.respond_to?(:call_versioned) }
418
+ mod&.call_versioned(name, signature, *args, &block)
419
+ end
420
+ end
421
+
422
+
423
+ # ============================================================
424
+ # 旧版本MonkeyPatch
425
+ # ============================================================
426
+
53
427
  class Object
54
428
  attr_accessor :main_version, :versions
55
429