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.
- checksums.yaml +4 -4
- data/README.md +29 -3
- data/cc.rb +1 -0
- data/monkey-patch.rb +375 -1
- data/text-client.rb +297 -0
- data/text-server.rb +403 -0
- data/text-tools.rb +418 -0
- data/tree.rb +184 -184
- metadata +5 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 560df541d3d489827cf9873d8ad9b78efb20e454824728462dff70fd955b477a
|
|
4
|
+
data.tar.gz: 235e3d4bc81f79b5bc3eb72303ef4df9ae1f724753a7484f451fff75b9f7bb53
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
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
|
|