mk_semi_lattice 0.1.1
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 +7 -0
- data/.DS_Store +0 -0
- data/.hyper_card/history/20251020_1517_readme_formatted.md +463 -0
- data/.hyper_card/history/20251020_1828_minor_rev_formatted.md +181 -0
- data/.hyper_card/history/20251021_1110_wsl_ubuntu_japanese.md +218 -0
- data/.hyper_card/history/20251021_1142_double_click_action.md +250 -0
- data/.hyper_card/history/20251021_1151_select_semi_data_action.md +75 -0
- data/.hyper_card/history/20251021_2322_add_comment_edges.md +252 -0
- data/.hyper_card/history/20251022_0725_add_color_index.md +155 -0
- data/.hyper_card/history/classify_251103.md +1090 -0
- data/.hyper_card/history/file_path_modifier.md +481 -0
- data/.hyper_card/history/file_path_modifier_251103.md +505 -0
- data/.hyper_card/history/knowledge_fixer.pdf +0 -0
- data/.hyper_card/history/log_with_symbol_251102.md +184 -0
- data/.hyper_card/history/memory_leak_251028.md +311 -0
- data/.hyper_card/history/set_log_conf_251027.md +295 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/LICENSE.txt +21 -0
- data/README.md +43 -0
- data/Rakefile +8 -0
- data/exe/mk_semi_lattice +3 -0
- data/exe/sl +5 -0
- data/lib/mk_semi_lattice/config.rb +53 -0
- data/lib/mk_semi_lattice/log.rb +26 -0
- data/lib/mk_semi_lattice/manage_yaml.rb +89 -0
- data/lib/mk_semi_lattice/mk_dir_yaml.rb +40 -0
- data/lib/mk_semi_lattice/mk_node_edge.rb +108 -0
- data/lib/mk_semi_lattice/mk_semi_lattice_graph.rb +254 -0
- data/lib/mk_semi_lattice/mk_semi_lattice_viewer.rb +77 -0
- data/lib/mk_semi_lattice/option_manager.rb +58 -0
- data/lib/mk_semi_lattice/ruby2d_action.rb +136 -0
- data/lib/mk_semi_lattice/version.rb +5 -0
- data/lib/mk_semi_lattice.rb +22 -0
- data/sig/mk_semi_lattice.rbs +4 -0
- metadata +122 -0
|
@@ -0,0 +1,1090 @@
|
|
|
1
|
+
# head
|
|
2
|
+
date: 2025-11-03
|
|
3
|
+
author: bob
|
|
4
|
+
|
|
5
|
+
## User
|
|
6
|
+
codeのrefactorを進めます.まずは,config関連の動作をclass Configにまとめて呼び出すようにしましょう.
|
|
7
|
+
|
|
8
|
+
## Copilot
|
|
9
|
+
以下のように`Config`クラスを新設し、設定ファイルの読み書きやディレクトリ作成、ログ有効化/無効化の管理をまとめます。
|
|
10
|
+
グローバル変数`$conf`や`CONF_PATH`なども`Config`クラスのクラス変数/メソッドで管理します。
|
|
11
|
+
|
|
12
|
+
````ruby
|
|
13
|
+
# ...existing code...
|
|
14
|
+
|
|
15
|
+
class Config
|
|
16
|
+
CONFIG_DIR = File.expand_path("~/.config/semi_lattice")
|
|
17
|
+
CONF_PATH = File.join(CONFIG_DIR, "semi_lattice.conf")
|
|
18
|
+
LOG_PATH = File.join(CONFIG_DIR, "semi_lattice_history")
|
|
19
|
+
|
|
20
|
+
@conf = { "log" => false }
|
|
21
|
+
|
|
22
|
+
class << self
|
|
23
|
+
attr_reader :conf
|
|
24
|
+
|
|
25
|
+
def setup
|
|
26
|
+
FileUtils.mkdir_p(CONFIG_DIR)
|
|
27
|
+
load_conf
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def load_conf
|
|
31
|
+
if File.file?(CONF_PATH)
|
|
32
|
+
begin
|
|
33
|
+
loaded = YAML.load_file(CONF_PATH)
|
|
34
|
+
if loaded.is_a?(Hash)
|
|
35
|
+
@conf.merge!(loaded)
|
|
36
|
+
else
|
|
37
|
+
puts "Warning: #{CONF_PATH} is not a hash. Using default config.".yellow
|
|
38
|
+
end
|
|
39
|
+
rescue
|
|
40
|
+
puts "Warning: #{CONF_PATH} is invalid. Using default config.".yellow
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def save_conf
|
|
46
|
+
File.write(CONF_PATH, @conf.to_yaml)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def log_enabled?
|
|
50
|
+
@conf["log"]
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def set_log(value)
|
|
54
|
+
@conf["log"] = value
|
|
55
|
+
save_conf
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def log_path
|
|
59
|
+
LOG_PATH
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
Config.setup
|
|
65
|
+
|
|
66
|
+
# ...existing code...
|
|
67
|
+
|
|
68
|
+
options = { layer: 2, init_step: :from_semi_lattice, show_index: false, merge: false }
|
|
69
|
+
OptionParser.new do |opts|
|
|
70
|
+
# ...existing code...
|
|
71
|
+
opts.on("-l", "--log [BOOL]", "Enable/disable logging (true/false), and save to config") do |v|
|
|
72
|
+
bool =
|
|
73
|
+
if v.nil?
|
|
74
|
+
true
|
|
75
|
+
elsif v.is_a?(String)
|
|
76
|
+
case v.strip.downcase
|
|
77
|
+
when "true", "yes", "on", "1"
|
|
78
|
+
true
|
|
79
|
+
when "false", "no", "off", "0"
|
|
80
|
+
false
|
|
81
|
+
else
|
|
82
|
+
puts "Invalid value for log: #{v}. Using default: false".yellow
|
|
83
|
+
false
|
|
84
|
+
end
|
|
85
|
+
else
|
|
86
|
+
!!v
|
|
87
|
+
end
|
|
88
|
+
Config.set_log(bool)
|
|
89
|
+
puts "Logging is now #{bool ? 'enabled' : 'disabled'} (saved to #{Config::CONF_PATH})"
|
|
90
|
+
exit
|
|
91
|
+
end
|
|
92
|
+
end.parse!
|
|
93
|
+
|
|
94
|
+
# ...existing code...
|
|
95
|
+
|
|
96
|
+
def log_event(action, target_dir: nil)
|
|
97
|
+
return unless Config.log_enabled?
|
|
98
|
+
log_entry = {
|
|
99
|
+
timestamp: Time.now.strftime('%Y-%m-%d %H:%M:%S'),
|
|
100
|
+
action: action
|
|
101
|
+
}
|
|
102
|
+
log_entry[:target_dir] = target_dir if target_dir
|
|
103
|
+
log_entry[:where] = $parent_dir
|
|
104
|
+
logs = []
|
|
105
|
+
if File.exist?(Config.log_path)
|
|
106
|
+
begin
|
|
107
|
+
logs = YAML.load_file(Config.log_path) || []
|
|
108
|
+
rescue
|
|
109
|
+
logs = []
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
logs << log_entry
|
|
113
|
+
File.write(Config.log_path, logs.to_yaml)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# ...existing code...
|
|
117
|
+
````
|
|
118
|
+
|
|
119
|
+
- これでconfig関連の処理が`Config`クラスに集約され、グローバル変数の使用も減ります。
|
|
120
|
+
- 他の箇所で`$conf`や`CONF_PATH`を参照していた場合は`Config.conf`や`Config::CONF_PATH`に置き換えてください。
|
|
121
|
+
|
|
122
|
+
## User
|
|
123
|
+
class Configを切り離して,lib/mk_semi_lattice/config.rbに移しましょう.
|
|
124
|
+
|
|
125
|
+
## Copilot
|
|
126
|
+
````ruby
|
|
127
|
+
# frozen_string_literal: true
|
|
128
|
+
require 'yaml'
|
|
129
|
+
require 'fileutils'
|
|
130
|
+
require 'colorize'
|
|
131
|
+
|
|
132
|
+
class Config
|
|
133
|
+
CONFIG_DIR = File.expand_path("~/.config/semi_lattice")
|
|
134
|
+
CONF_PATH = File.join(CONFIG_DIR, "semi_lattice.conf")
|
|
135
|
+
LOG_PATH = File.join(CONFIG_DIR, "semi_lattice_history")
|
|
136
|
+
|
|
137
|
+
@conf = { "log" => false }
|
|
138
|
+
|
|
139
|
+
class << self
|
|
140
|
+
attr_reader :conf
|
|
141
|
+
|
|
142
|
+
def setup
|
|
143
|
+
FileUtils.mkdir_p(CONFIG_DIR)
|
|
144
|
+
load_conf
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def load_conf
|
|
148
|
+
if File.file?(CONF_PATH)
|
|
149
|
+
begin
|
|
150
|
+
loaded = YAML.load_file(CONF_PATH)
|
|
151
|
+
if loaded.is_a?(Hash)
|
|
152
|
+
@conf.merge!(loaded)
|
|
153
|
+
else
|
|
154
|
+
puts "Warning: #{CONF_PATH} is not a hash. Using default config.".yellow
|
|
155
|
+
end
|
|
156
|
+
rescue
|
|
157
|
+
puts "Warning: #{CONF_PATH} is invalid. Using default config.".yellow
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def save_conf
|
|
163
|
+
File.write(CONF_PATH, @conf.to_yaml)
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def log_enabled?
|
|
167
|
+
@conf["log"]
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def set_log(value)
|
|
171
|
+
@conf["log"] = value
|
|
172
|
+
save_conf
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def log_path
|
|
176
|
+
LOG_PATH
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
````
|
|
181
|
+
|
|
182
|
+
そして、mk_semi_lattice.rbの先頭付近で次のように修正してください。
|
|
183
|
+
|
|
184
|
+
````ruby
|
|
185
|
+
# ...existing code...
|
|
186
|
+
require_relative "mk_semi_lattice/config"
|
|
187
|
+
# ...class Configの定義を削除...
|
|
188
|
+
Config.setup
|
|
189
|
+
# ...existing code...
|
|
190
|
+
````
|
|
191
|
+
|
|
192
|
+
これで`Config`クラスが分離され、他のファイルからも`require_relative "mk_semi_lattice/config"`で利用できます。
|
|
193
|
+
|
|
194
|
+
## User
|
|
195
|
+
#file:mk_semi_lattice.rb:12-69 あたりも修正を反映させて.
|
|
196
|
+
|
|
197
|
+
## Copilot
|
|
198
|
+
````ruby
|
|
199
|
+
# ...existing code...
|
|
200
|
+
require_relative "mk_semi_lattice/version"
|
|
201
|
+
require_relative "mk_semi_lattice/mk_dir_yaml"
|
|
202
|
+
require_relative "mk_semi_lattice/mk_node_edge"
|
|
203
|
+
require_relative "mk_semi_lattice/mk_semi_lattice_graph"
|
|
204
|
+
require_relative "mk_semi_lattice/config" # ← 追加
|
|
205
|
+
|
|
206
|
+
$semi_dir = ''
|
|
207
|
+
class Error < StandardError; end
|
|
208
|
+
|
|
209
|
+
puts "mk_semi_lattice is running..."
|
|
210
|
+
|
|
211
|
+
# ↓↓↓ ここ(class Config ... end)は削除してください ↓↓↓
|
|
212
|
+
# class Config
|
|
213
|
+
# CONFIG_DIR = File.expand_path("~/.config/semi_lattice")
|
|
214
|
+
# CONF_PATH = File.join(CONFIG_DIR, "semi_lattice.conf")
|
|
215
|
+
# LOG_PATH = File.join(CONFIG_DIR, "semi_lattice_history")
|
|
216
|
+
# ...
|
|
217
|
+
# end
|
|
218
|
+
|
|
219
|
+
Config.setup
|
|
220
|
+
# ...existing code...
|
|
221
|
+
````
|
|
222
|
+
|
|
223
|
+
- `class Config ... end` の定義を削除し、
|
|
224
|
+
- 代わりに `require_relative "mk_semi_lattice/config"` を追加してください。
|
|
225
|
+
- 以降の `Config.setup` や `Config.xxx` の呼び出しはそのまま使えます。
|
|
226
|
+
|
|
227
|
+
この修正で、`Config` クラスは config.rb から読み込まれるようになります。
|
|
228
|
+
|
|
229
|
+
## User
|
|
230
|
+
#file:mk_semi_lattice.rb:72-96 を分離してclass Logを作成
|
|
231
|
+
|
|
232
|
+
## Copilot
|
|
233
|
+
````ruby
|
|
234
|
+
# frozen_string_literal: true
|
|
235
|
+
require 'yaml'
|
|
236
|
+
|
|
237
|
+
class Log
|
|
238
|
+
class << self
|
|
239
|
+
def event(action, target_dir: nil, parent_dir: Dir.pwd)
|
|
240
|
+
return unless Config.log_enabled?
|
|
241
|
+
log_entry = {
|
|
242
|
+
timestamp: Time.now.strftime('%Y-%m-%d %H:%M:%S'),
|
|
243
|
+
action: action
|
|
244
|
+
}
|
|
245
|
+
log_entry[:target_dir] = target_dir if target_dir
|
|
246
|
+
log_entry[:where] = parent_dir
|
|
247
|
+
logs = []
|
|
248
|
+
if File.exist?(Config.log_path)
|
|
249
|
+
begin
|
|
250
|
+
logs = YAML.load_file(Config.log_path) || []
|
|
251
|
+
rescue
|
|
252
|
+
logs = []
|
|
253
|
+
end
|
|
254
|
+
end
|
|
255
|
+
logs << log_entry
|
|
256
|
+
File.write(Config.log_path, logs.to_yaml)
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
````
|
|
261
|
+
|
|
262
|
+
**使い方(lib/mk_semi_lattice.rb側の修正例):**
|
|
263
|
+
|
|
264
|
+
````ruby
|
|
265
|
+
# ...existing code...
|
|
266
|
+
require_relative "mk_semi_lattice/log"
|
|
267
|
+
|
|
268
|
+
# ...existing code...
|
|
269
|
+
|
|
270
|
+
Log.event("started", parent_dir: $parent_dir)
|
|
271
|
+
|
|
272
|
+
# ...log_event("open", ...) → Log.event("open", target_dir: ..., parent_dir: $parent_dir)
|
|
273
|
+
# ...log_event("exited") → Log.event("exited", parent_dir: $parent_dir)
|
|
274
|
+
````
|
|
275
|
+
|
|
276
|
+
- これでログ機能が`Log`クラスに分離され、`Log.event`で呼び出せます。
|
|
277
|
+
- `$parent_dir`は必要に応じて引数で渡してください(デフォルトは`Dir.pwd`)。
|
|
278
|
+
|
|
279
|
+
## User
|
|
280
|
+
#file:mk_semi_lattice.rb:72-96 を変更を反映.
|
|
281
|
+
|
|
282
|
+
## Copilot
|
|
283
|
+
````ruby
|
|
284
|
+
# ...existing code...
|
|
285
|
+
require_relative "mk_semi_lattice/log"
|
|
286
|
+
# ...existing code...
|
|
287
|
+
|
|
288
|
+
# LOG_DIR, LOG_PATH, log_eventメソッドを削除
|
|
289
|
+
|
|
290
|
+
Log.event("started", parent_dir: $parent_dir)
|
|
291
|
+
# ...existing code...
|
|
292
|
+
````
|
|
293
|
+
|
|
294
|
+
**新規ファイル:**
|
|
295
|
+
|
|
296
|
+
````ruby
|
|
297
|
+
# frozen_string_literal: true
|
|
298
|
+
require 'yaml'
|
|
299
|
+
|
|
300
|
+
class Log
|
|
301
|
+
class << self
|
|
302
|
+
def event(action, target_dir: nil, parent_dir: Dir.pwd)
|
|
303
|
+
return unless Config.log_enabled?
|
|
304
|
+
log_entry = {
|
|
305
|
+
timestamp: Time.now.strftime('%Y-%m-%d %H:%M:%S'),
|
|
306
|
+
action: action
|
|
307
|
+
}
|
|
308
|
+
log_entry[:target_dir] = target_dir if target_dir
|
|
309
|
+
log_entry[:where] = parent_dir
|
|
310
|
+
logs = []
|
|
311
|
+
if File.exist?(Config.log_path)
|
|
312
|
+
begin
|
|
313
|
+
logs = YAML.load_file(Config.log_path) || []
|
|
314
|
+
rescue
|
|
315
|
+
logs = []
|
|
316
|
+
end
|
|
317
|
+
end
|
|
318
|
+
logs << log_entry
|
|
319
|
+
File.write(Config.log_path, logs.to_yaml)
|
|
320
|
+
end
|
|
321
|
+
end
|
|
322
|
+
end
|
|
323
|
+
````
|
|
324
|
+
|
|
325
|
+
**ポイント:**
|
|
326
|
+
- `log_event`の呼び出しはすべて`Log.event`に置き換えてください(例: `Log.event("open", target_dir: ..., parent_dir: $parent_dir)`)。
|
|
327
|
+
- `LOG_DIR`や`LOG_PATH`の定義も不要です(`Config`クラスで管理)。
|
|
328
|
+
- `require_relative "mk_semi_lattice/log"`を忘れずに追加してください。
|
|
329
|
+
|
|
330
|
+
## User
|
|
331
|
+
/Users/bob/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/mk_semi_lattice-0.1.0/lib/mk_semi_lattice.rb:261:in `block in <top (required)>': undefined method `log_event' for main:Object (NoMethodError)
|
|
332
|
+
/Users/bob/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/mk_semi_lattice-0.1.0/lib/mk_semi_lattice.rb:169:in `double_click_action': undefined method `log_event' for main:Object (NoMethodError)
|
|
333
|
+
となっています.
|
|
334
|
+
|
|
335
|
+
## Copilot
|
|
336
|
+
`log_event`メソッドを`Log.event`に置き換える必要があります。
|
|
337
|
+
`log_event(...)`を呼んでいる箇所をすべて`Log.event(...)`に修正してください。
|
|
338
|
+
|
|
339
|
+
例:
|
|
340
|
+
|
|
341
|
+
````ruby
|
|
342
|
+
# ...existing code...
|
|
343
|
+
|
|
344
|
+
# 例: 起動時
|
|
345
|
+
Log.event("started", parent_dir: $parent_dir)
|
|
346
|
+
|
|
347
|
+
# 例: ダブルクリックアクション内
|
|
348
|
+
Log.event("open", target_dir: File.expand_path(ファイルパス, $parent_dir), parent_dir: $parent_dir)
|
|
349
|
+
|
|
350
|
+
# 例: 終了時
|
|
351
|
+
Log.event("exited", parent_dir: $parent_dir)
|
|
352
|
+
# ...existing code...
|
|
353
|
+
````
|
|
354
|
+
|
|
355
|
+
**ポイント**
|
|
356
|
+
- `log_event`というメソッドはもう存在しません。
|
|
357
|
+
- 代わりに`Log.event`を使ってください。
|
|
358
|
+
- `require_relative "mk_semi_lattice/log"`がファイル冒頭に必要です。
|
|
359
|
+
|
|
360
|
+
**例: ダブルクリックアクションの修正例**
|
|
361
|
+
````ruby
|
|
362
|
+
# ...existing code...
|
|
363
|
+
def double_click_action(clicked_node)
|
|
364
|
+
comm = nil
|
|
365
|
+
if clicked_node.file_path
|
|
366
|
+
# ...省略...
|
|
367
|
+
Log.event("open", target_dir: File.expand_path(clicked_node.file_path, $parent_dir), parent_dir: $parent_dir)
|
|
368
|
+
system comm
|
|
369
|
+
else
|
|
370
|
+
puts "no link error"
|
|
371
|
+
end
|
|
372
|
+
end
|
|
373
|
+
# ...existing code...
|
|
374
|
+
````
|
|
375
|
+
|
|
376
|
+
この修正でエラーは解消します。
|
|
377
|
+
|
|
378
|
+
## User
|
|
379
|
+
/Users/bob/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/mk_semi_lattice-0.1.0/lib/mk_semi_lattice.rb:72:in `<top (required)>': uninitialized constant CONFIG_DIR (NameError)
|
|
380
|
+
Did you mean? Config
|
|
381
|
+
とエラーが出てます.
|
|
382
|
+
|
|
383
|
+
## Copilot
|
|
384
|
+
`CONFIG_DIR`や`LOG_PATH`などの定数は、すでに`Config`クラスで管理されています。
|
|
385
|
+
mk_semi_lattice.rb内の以下の部分は不要なので削除してください。
|
|
386
|
+
|
|
387
|
+
```ruby
|
|
388
|
+
LOG_DIR = CONFIG_DIR
|
|
389
|
+
Dir.mkdir_p(LOG_DIR) unless Dir.exist?(LOG_DIR)
|
|
390
|
+
LOG_PATH = File.join(LOG_DIR, "semi_lattice_history") # 拡張子なし
|
|
391
|
+
|
|
392
|
+
def log_event(action, target_dir: nil)
|
|
393
|
+
# ...省略...
|
|
394
|
+
end
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
また、`log_event(...)`の呼び出しもすべて削除し、`Log.event(...)`のみを使ってください。
|
|
398
|
+
|
|
399
|
+
**修正例:**
|
|
400
|
+
|
|
401
|
+
````ruby
|
|
402
|
+
# ...既存のrequireの下に追加...
|
|
403
|
+
require_relative "mk_semi_lattice/log"
|
|
404
|
+
# ...既存コード...
|
|
405
|
+
|
|
406
|
+
# ↓↓↓ この部分を削除してください ↓↓↓
|
|
407
|
+
# LOG_DIR = CONFIG_DIR
|
|
408
|
+
# Dir.mkdir_p(LOG_DIR) unless Dir.exist?(LOG_DIR)
|
|
409
|
+
# LOG_PATH = File.join(LOG_DIR, "semi_lattice_history") # 拡張子なし
|
|
410
|
+
#
|
|
411
|
+
# def log_event(action, target_dir: nil)
|
|
412
|
+
# ...
|
|
413
|
+
# end
|
|
414
|
+
|
|
415
|
+
# ...既存コード...
|
|
416
|
+
|
|
417
|
+
# 例: 起動時
|
|
418
|
+
Log.event("started", parent_dir: $parent_dir)
|
|
419
|
+
|
|
420
|
+
# log_event("started") ← これも削除
|
|
421
|
+
|
|
422
|
+
# ...ダブルクリックアクション内...
|
|
423
|
+
Log.event("open", target_dir: File.expand_path(clicked_node.file_path, $parent_dir), parent_dir: $parent_dir)
|
|
424
|
+
# log_event("open", ...) ← これも削除
|
|
425
|
+
|
|
426
|
+
# ...終了時...
|
|
427
|
+
Log.event("exited", parent_dir: $parent_dir)
|
|
428
|
+
# log_event("exited") ← これも削除
|
|
429
|
+
|
|
430
|
+
# ...既存コード...
|
|
431
|
+
````
|
|
432
|
+
|
|
433
|
+
**ポイント**
|
|
434
|
+
- `CONFIG_DIR`や`LOG_PATH`は`Config`クラスで管理されているので、直接参照しないでください。
|
|
435
|
+
- ログ記録は`Log.event`のみを使ってください。
|
|
436
|
+
- `require_relative "mk_semi_lattice/log"`を忘れずに。
|
|
437
|
+
|
|
438
|
+
この修正で`uninitialized constant CONFIG_DIR`エラーは解消します。
|
|
439
|
+
|
|
440
|
+
## User
|
|
441
|
+
#selectionを管理するclass OptionManagerを作成して分離.
|
|
442
|
+
|
|
443
|
+
## Copilot
|
|
444
|
+
````ruby
|
|
445
|
+
# frozen_string_literal: true
|
|
446
|
+
require 'optparse'
|
|
447
|
+
require 'colorize'
|
|
448
|
+
|
|
449
|
+
class OptionManager
|
|
450
|
+
attr_reader :options
|
|
451
|
+
|
|
452
|
+
def initialize
|
|
453
|
+
@options = { layer: 2, init_step: :from_semi_lattice, show_index: false, merge: false }
|
|
454
|
+
end
|
|
455
|
+
|
|
456
|
+
def parse!
|
|
457
|
+
OptionParser.new do |opts|
|
|
458
|
+
opts.banner = "Usage: mk_semi_lattice PATH [-L layer] [-t FILE] [-n FILE]\n default PATH = '.'"
|
|
459
|
+
|
|
460
|
+
opts.on("-L N", Integer, "Layer depth (default: 2)") do |v|
|
|
461
|
+
@options[:layer] = v
|
|
462
|
+
end
|
|
463
|
+
|
|
464
|
+
opts.on("-n", "--node=FILE", "using File from node-edge") do |file|
|
|
465
|
+
@options[:file] = file
|
|
466
|
+
@options[:init_step] = :from_node_edge
|
|
467
|
+
end
|
|
468
|
+
|
|
469
|
+
opts.on("-t", "--tree=FILE", "using File from tree") do |file|
|
|
470
|
+
@options[:file] = file
|
|
471
|
+
@options[:init_step] = :from_tree
|
|
472
|
+
end
|
|
473
|
+
|
|
474
|
+
opts.on("-i", "--index", "Display node ids") do
|
|
475
|
+
@options[:show_index] = true
|
|
476
|
+
end
|
|
477
|
+
|
|
478
|
+
opts.on("-l", "--log [BOOL]", "Enable/disable logging (true/false), and save to config") do |v|
|
|
479
|
+
bool =
|
|
480
|
+
if v.nil?
|
|
481
|
+
true
|
|
482
|
+
elsif v.is_a?(String)
|
|
483
|
+
case v.strip.downcase
|
|
484
|
+
when "true", "yes", "on", "1"
|
|
485
|
+
true
|
|
486
|
+
when "false", "no", "off", "0"
|
|
487
|
+
false
|
|
488
|
+
else
|
|
489
|
+
puts "Invalid value for log: #{v}. Using default: false".yellow
|
|
490
|
+
false
|
|
491
|
+
end
|
|
492
|
+
else
|
|
493
|
+
!!v
|
|
494
|
+
end
|
|
495
|
+
Config.set_log(bool)
|
|
496
|
+
puts "Logging is now #{bool ? 'enabled' : 'disabled'} (saved to #{Config::CONF_PATH})"
|
|
497
|
+
exit
|
|
498
|
+
end
|
|
499
|
+
end.parse!
|
|
500
|
+
@options
|
|
501
|
+
end
|
|
502
|
+
end
|
|
503
|
+
````
|
|
504
|
+
|
|
505
|
+
**mk_semi_lattice.rb 側の修正例:**
|
|
506
|
+
|
|
507
|
+
````ruby
|
|
508
|
+
require_relative "mk_semi_lattice/option_manager"
|
|
509
|
+
# ...existing code...
|
|
510
|
+
|
|
511
|
+
option_manager = OptionManager.new
|
|
512
|
+
options = option_manager.parse!
|
|
513
|
+
|
|
514
|
+
# 以降は options をそのまま利用
|
|
515
|
+
````
|
|
516
|
+
|
|
517
|
+
このようにすることで、コマンドラインオプションの管理が`OptionManager`クラスに集約され、mk_semi_lattice.rbがすっきりします。
|
|
518
|
+
|
|
519
|
+
## User
|
|
520
|
+
#file:mk_semi_lattice.rb:32-51 はLog.eventに代替しませんでしたっけ?
|
|
521
|
+
|
|
522
|
+
## Copilot
|
|
523
|
+
はい、その通りです。
|
|
524
|
+
`log_event`メソッド(#file:mk_semi_lattice.rb:32-51)は**不要**です。
|
|
525
|
+
すでに`Log.event`で代替されているので、**このメソッド定義は削除してください**。
|
|
526
|
+
|
|
527
|
+
修正例:
|
|
528
|
+
|
|
529
|
+
````ruby
|
|
530
|
+
# ...existing code...
|
|
531
|
+
|
|
532
|
+
# ↓↓↓ この部分を削除してください ↓↓↓
|
|
533
|
+
# def log_event(action, target_dir: nil)
|
|
534
|
+
# return unless Config.log_enabled?
|
|
535
|
+
# log_entry = {
|
|
536
|
+
# timestamp: Time.now.strftime('%Y-%m-%d %H:%M:%S'),
|
|
537
|
+
# action: action
|
|
538
|
+
# }
|
|
539
|
+
# log_entry[:target_dir] = target_dir if target_dir
|
|
540
|
+
# log_entry[:where] = $parent_dir
|
|
541
|
+
# logs = []
|
|
542
|
+
# if File.exist?(Config.log_path)
|
|
543
|
+
# begin
|
|
544
|
+
# logs = YAML.load_file(Config.log_path) || []
|
|
545
|
+
# rescue
|
|
546
|
+
# logs = []
|
|
547
|
+
# end
|
|
548
|
+
# end
|
|
549
|
+
# logs << log_entry
|
|
550
|
+
# File.write(Config.log_path, logs.to_yaml)
|
|
551
|
+
# end
|
|
552
|
+
|
|
553
|
+
# ...existing code...
|
|
554
|
+
````
|
|
555
|
+
|
|
556
|
+
以降は`Log.event(...)`のみを使ってください。
|
|
557
|
+
|
|
558
|
+
## User
|
|
559
|
+
#file:mk_semi_lattice.rb:35-74 の動作をまとめてclass SelectYamlを作成
|
|
560
|
+
|
|
561
|
+
## Copilot
|
|
562
|
+
````ruby
|
|
563
|
+
# frozen_string_literal: true
|
|
564
|
+
|
|
565
|
+
module MkSemiLattice
|
|
566
|
+
class SelectYaml
|
|
567
|
+
def initialize(parent_dir:, semi_dir:, semi_lattice_yaml_path:, options:)
|
|
568
|
+
@parent_dir = parent_dir
|
|
569
|
+
@semi_dir = semi_dir
|
|
570
|
+
@semi_lattice_yaml_path = semi_lattice_yaml_path
|
|
571
|
+
@options = options
|
|
572
|
+
end
|
|
573
|
+
|
|
574
|
+
# ARGV[0]とoptionsから初期ファイル・初期ステップを決定
|
|
575
|
+
def select_init_file_and_step
|
|
576
|
+
if (ARGV[0] == '.' || ARGV[0].nil?) && !@options[:file]
|
|
577
|
+
if File.exist?(@semi_lattice_yaml_path)
|
|
578
|
+
[@semi_lattice_yaml_path, :from_semi_lattice]
|
|
579
|
+
else
|
|
580
|
+
['.', :from_dir]
|
|
581
|
+
end
|
|
582
|
+
else
|
|
583
|
+
[ARGV[0], @options[:init_step]]
|
|
584
|
+
end
|
|
585
|
+
end
|
|
586
|
+
|
|
587
|
+
# 初期ステップに応じて入力ファイルとwith_semi_lattice_yamlを決定
|
|
588
|
+
def select_input_path_and_flag(init_file, init_step)
|
|
589
|
+
case init_step
|
|
590
|
+
when :from_dir
|
|
591
|
+
Dir.mkdir(@semi_dir) unless Dir.exist?(@semi_dir)
|
|
592
|
+
in_path = init_file
|
|
593
|
+
out_path = File.join(@semi_dir, 'dir_tree.yaml')
|
|
594
|
+
MkSemiLattice::MkDirYaml.new(path: in_path, layer: @options[:layer], output_file: out_path)
|
|
595
|
+
in_path = out_path
|
|
596
|
+
out_path = File.join(@semi_dir, 'dir_node_edge.yaml')
|
|
597
|
+
MkSemiLattice::MkNodeEdge.new(input_path: in_path, output_path: out_path)
|
|
598
|
+
[out_path, false]
|
|
599
|
+
when :from_tree
|
|
600
|
+
init_file = @options[:file]
|
|
601
|
+
base = File.basename(init_file, File.extname(init_file))
|
|
602
|
+
in_path = init_file
|
|
603
|
+
out_path = File.join(@parent_dir, "#{base}_node_edge.yaml")
|
|
604
|
+
MkSemiLattice::MkNodeEdge.new(input_path: in_path, output_path: out_path)
|
|
605
|
+
[out_path, false]
|
|
606
|
+
when :from_node_edge
|
|
607
|
+
if File.exist?(File.join(@parent_dir, 'semi_lattice.yaml'))
|
|
608
|
+
puts "Warning: semi_lattice.yaml already exists in current directory.".yellow
|
|
609
|
+
exit 1
|
|
610
|
+
end
|
|
611
|
+
[@options[:file], false]
|
|
612
|
+
when :from_semi_lattice
|
|
613
|
+
[init_file, true]
|
|
614
|
+
else
|
|
615
|
+
raise "Unknown init_step: #{init_step}"
|
|
616
|
+
end
|
|
617
|
+
end
|
|
618
|
+
end
|
|
619
|
+
end
|
|
620
|
+
````
|
|
621
|
+
|
|
622
|
+
**mk_semi_lattice.rb 側の利用例:**
|
|
623
|
+
|
|
624
|
+
````ruby
|
|
625
|
+
require_relative "mk_semi_lattice/select_yaml"
|
|
626
|
+
# ...existing code...
|
|
627
|
+
|
|
628
|
+
selector = MkSemiLattice::SelectYaml.new(
|
|
629
|
+
parent_dir: $parent_dir,
|
|
630
|
+
semi_dir: semi_dir,
|
|
631
|
+
semi_lattice_yaml_path: semi_lattice_yaml_path,
|
|
632
|
+
options: options
|
|
633
|
+
)
|
|
634
|
+
init_file, init_step = selector.select_init_file_and_step
|
|
635
|
+
p [init_file, init_step]
|
|
636
|
+
input_path, with_semi_lattice_yaml = selector.select_input_path_and_flag(init_file, init_step)
|
|
637
|
+
p [input_path, with_semi_lattice_yaml]
|
|
638
|
+
|
|
639
|
+
# ...existing code...
|
|
640
|
+
````
|
|
641
|
+
|
|
642
|
+
このように分離することで、初期ファイル・初期ステップの選択ロジックが`SelectYaml`クラスにまとまります。
|
|
643
|
+
|
|
644
|
+
## User
|
|
645
|
+
#file:mk_semi_lattice.rb:160-192 の動作を行う関数def at_exit_actionを作成.
|
|
646
|
+
|
|
647
|
+
## Copilot
|
|
648
|
+
````ruby
|
|
649
|
+
# ...existing code...
|
|
650
|
+
|
|
651
|
+
def at_exit_action(app, semi_dir, parent_dir)
|
|
652
|
+
nodes_data = app.nodes.map do |n|
|
|
653
|
+
p [n.label, n.fixed, n.color]
|
|
654
|
+
{
|
|
655
|
+
id: app.node_table.key(n),
|
|
656
|
+
name: n.name,
|
|
657
|
+
type: n.type,
|
|
658
|
+
file_path: n.file_path,
|
|
659
|
+
x: n.x,
|
|
660
|
+
y: n.y,
|
|
661
|
+
color: n.color,
|
|
662
|
+
fixed: n.fixed
|
|
663
|
+
}
|
|
664
|
+
end
|
|
665
|
+
edges_data = app.edges.map do |e|
|
|
666
|
+
{
|
|
667
|
+
from: app.node_table.key(e.from),
|
|
668
|
+
to: app.node_table.key(e.to)
|
|
669
|
+
}
|
|
670
|
+
end
|
|
671
|
+
|
|
672
|
+
yaml_data = { nodes: nodes_data, edges: edges_data }
|
|
673
|
+
yaml_text = MkSemiLattice::MkNodeEdge.add_edge_comments(yaml_data)
|
|
674
|
+
if Dir.exist?(semi_dir)
|
|
675
|
+
File.write(File.join(semi_dir, "semi_lattice.yaml"), yaml_text)
|
|
676
|
+
else
|
|
677
|
+
File.write(File.join('.', "semi_lattice.yaml"), yaml_text)
|
|
678
|
+
end
|
|
679
|
+
Log.event("exited", parent_dir: parent_dir)
|
|
680
|
+
end
|
|
681
|
+
|
|
682
|
+
# ...existing code...
|
|
683
|
+
|
|
684
|
+
at_exit do
|
|
685
|
+
at_exit_action(app, semi_dir, $parent_dir)
|
|
686
|
+
end
|
|
687
|
+
|
|
688
|
+
# ...existing code...
|
|
689
|
+
````
|
|
690
|
+
|
|
691
|
+
このように関数化することで、`at_exit`ブロックがすっきりします。
|
|
692
|
+
|
|
693
|
+
## User
|
|
694
|
+
at_exit_actionをSelectYamlに入れることは可能ですか?
|
|
695
|
+
|
|
696
|
+
## Copilot
|
|
697
|
+
はい、`at_exit_action`を`SelectYaml`に入れることは**技術的には可能**ですが、設計上はあまりおすすめしません。
|
|
698
|
+
|
|
699
|
+
### 理由
|
|
700
|
+
- `SelectYaml`は「初期ファイルや初期ステップの選択」を担当するクラスです。
|
|
701
|
+
- `at_exit_action`は「アプリの状態(ノード・エッジ)をYAMLに保存する」責務であり、役割が異なります。
|
|
702
|
+
- 責務分離の観点から、`at_exit_action`は`SelectYaml`ではなく、例えば`MkSemiLatticeData`のインスタンスメソッドや、専用の`Saver`クラスなどに分離するのが自然です。
|
|
703
|
+
|
|
704
|
+
---
|
|
705
|
+
|
|
706
|
+
### どうしても`SelectYaml`に入れたい場合
|
|
707
|
+
|
|
708
|
+
- クラスメソッドやインスタンスメソッドとして追加はできます。
|
|
709
|
+
- ただし、`SelectYaml`の責務が曖昧になり、保守性が下がります。
|
|
710
|
+
|
|
711
|
+
#### 例(クラスメソッドとして追加):
|
|
712
|
+
|
|
713
|
+
````ruby
|
|
714
|
+
module MkSemiLattice
|
|
715
|
+
class SelectYaml
|
|
716
|
+
# ...既存コード...
|
|
717
|
+
|
|
718
|
+
def self.at_exit_action(app, semi_dir, parent_dir)
|
|
719
|
+
nodes_data = app.nodes.map do |n|
|
|
720
|
+
{
|
|
721
|
+
id: app.node_table.key(n),
|
|
722
|
+
name: n.name,
|
|
723
|
+
type: n.type,
|
|
724
|
+
file_path: n.file_path,
|
|
725
|
+
x: n.x,
|
|
726
|
+
y: n.y,
|
|
727
|
+
color: n.color,
|
|
728
|
+
fixed: n.fixed
|
|
729
|
+
}
|
|
730
|
+
end
|
|
731
|
+
edges_data = app.edges.map do |e|
|
|
732
|
+
{
|
|
733
|
+
from: app.node_table.key(e.from),
|
|
734
|
+
to: app.node_table.key(e.to)
|
|
735
|
+
}
|
|
736
|
+
end
|
|
737
|
+
|
|
738
|
+
yaml_data = { nodes: nodes_data, edges: edges_data }
|
|
739
|
+
yaml_text = MkSemiLattice::MkNodeEdge.add_edge_comments(yaml_data)
|
|
740
|
+
if Dir.exist?(semi_dir)
|
|
741
|
+
File.write(File.join(semi_dir, "semi_lattice.yaml"), yaml_text)
|
|
742
|
+
else
|
|
743
|
+
File.write(File.join('.', "semi_lattice.yaml"), yaml_text)
|
|
744
|
+
end
|
|
745
|
+
Log.event("exited", parent_dir: parent_dir)
|
|
746
|
+
end
|
|
747
|
+
end
|
|
748
|
+
end
|
|
749
|
+
````
|
|
750
|
+
|
|
751
|
+
**呼び出し側:**
|
|
752
|
+
|
|
753
|
+
````ruby
|
|
754
|
+
at_exit do
|
|
755
|
+
MkSemiLattice::SelectYaml.at_exit_action(app, semi_dir, $parent_dir)
|
|
756
|
+
end
|
|
757
|
+
````
|
|
758
|
+
|
|
759
|
+
---
|
|
760
|
+
|
|
761
|
+
### 結論
|
|
762
|
+
|
|
763
|
+
- **可能だが、設計上は推奨しません。**
|
|
764
|
+
- 責務分離のため、保存処理は別クラスや`MkSemiLatticeData`のメソッドにするのがベターです。
|
|
765
|
+
|
|
766
|
+
## User
|
|
767
|
+
MkSemiLatticeDataをMkSemiLatticeGraphDataに変更
|
|
768
|
+
|
|
769
|
+
## Copilot
|
|
770
|
+
````ruby
|
|
771
|
+
# ...existing code...
|
|
772
|
+
class MkSemiLatticeGraphData
|
|
773
|
+
attr_reader :nodes, :edges, :node_table
|
|
774
|
+
attr_accessor :selected, :shift_pressed, :show_index
|
|
775
|
+
|
|
776
|
+
def initialize(file = "dir_node_edge.yaml", with_semi_lattice_yaml: false, show_index: false)
|
|
777
|
+
@nodes = []
|
|
778
|
+
@edges = []
|
|
779
|
+
@node_table = {}
|
|
780
|
+
@selected = nil
|
|
781
|
+
@shift_pressed = false
|
|
782
|
+
p @show_index = show_index
|
|
783
|
+
load_yaml_data_with_state(file, with_semi_lattice_yaml: with_semi_lattice_yaml)
|
|
784
|
+
end
|
|
785
|
+
|
|
786
|
+
# ...以下同じ...
|
|
787
|
+
end
|
|
788
|
+
````
|
|
789
|
+
|
|
790
|
+
````ruby
|
|
791
|
+
# ...existing code...
|
|
792
|
+
|
|
793
|
+
app = MkSemiLatticeGraphData.new(input_path,
|
|
794
|
+
with_semi_lattice_yaml: with_semi_lattice_yaml,
|
|
795
|
+
show_index: options[:show_index]
|
|
796
|
+
)
|
|
797
|
+
|
|
798
|
+
# ...existing code...
|
|
799
|
+
````
|
|
800
|
+
|
|
801
|
+
- `MkSemiLatticeData` → `MkSemiLatticeGraphData` にクラス名を変更してください。
|
|
802
|
+
- インスタンス生成も同様に変更してください。
|
|
803
|
+
|
|
804
|
+
## User
|
|
805
|
+
SelectYamlをManageYamlに変更.
|
|
806
|
+
|
|
807
|
+
## Copilot
|
|
808
|
+
````ruby
|
|
809
|
+
# frozen_string_literal: true
|
|
810
|
+
|
|
811
|
+
module MkSemiLattice
|
|
812
|
+
class ManageYaml
|
|
813
|
+
def initialize(parent_dir:, semi_dir:, semi_lattice_yaml_path:, options:)
|
|
814
|
+
@parent_dir = parent_dir
|
|
815
|
+
@semi_dir = semi_dir
|
|
816
|
+
@semi_lattice_yaml_path = semi_lattice_yaml_path
|
|
817
|
+
@options = options
|
|
818
|
+
end
|
|
819
|
+
|
|
820
|
+
# ARGV[0]とoptionsから初期ファイル・初期ステップを決定
|
|
821
|
+
def select_init_file_and_step
|
|
822
|
+
if (ARGV[0] == '.' || ARGV[0].nil?) && !@options[:file]
|
|
823
|
+
if File.exist?(@semi_lattice_yaml_path)
|
|
824
|
+
[@semi_lattice_yaml_path, :from_semi_lattice]
|
|
825
|
+
else
|
|
826
|
+
['.', :from_dir]
|
|
827
|
+
end
|
|
828
|
+
else
|
|
829
|
+
[ARGV[0], @options[:init_step]]
|
|
830
|
+
end
|
|
831
|
+
end
|
|
832
|
+
|
|
833
|
+
# 初期ステップに応じて入力ファイルとwith_semi_lattice_yamlを決定
|
|
834
|
+
def select_input_path_and_flag(init_file, init_step)
|
|
835
|
+
case init_step
|
|
836
|
+
when :from_dir
|
|
837
|
+
Dir.mkdir(@semi_dir) unless Dir.exist?(@semi_dir)
|
|
838
|
+
in_path = init_file
|
|
839
|
+
out_path = File.join(@semi_dir, 'dir_tree.yaml')
|
|
840
|
+
MkSemiLattice::MkDirYaml.new(path: in_path, layer: @options[:layer], output_file: out_path)
|
|
841
|
+
in_path = out_path
|
|
842
|
+
out_path = File.join(@semi_dir, 'dir_node_edge.yaml')
|
|
843
|
+
MkSemiLattice::MkNodeEdge.new(input_path: in_path, output_path: out_path)
|
|
844
|
+
[out_path, false]
|
|
845
|
+
when :from_tree
|
|
846
|
+
init_file = @options[:file]
|
|
847
|
+
base = File.basename(init_file, File.extname(init_file))
|
|
848
|
+
in_path = init_file
|
|
849
|
+
out_path = File.join(@parent_dir, "#{base}_node_edge.yaml")
|
|
850
|
+
MkSemiLattice::MkNodeEdge.new(input_path: in_path, output_path: out_path)
|
|
851
|
+
[out_path, false]
|
|
852
|
+
when :from_node_edge
|
|
853
|
+
if File.exist?(File.join(@parent_dir, 'semi_lattice.yaml'))
|
|
854
|
+
puts "Warning: semi_lattice.yaml already exists in current directory.".yellow
|
|
855
|
+
exit 1
|
|
856
|
+
end
|
|
857
|
+
[@options[:file], false]
|
|
858
|
+
when :from_semi_lattice
|
|
859
|
+
[init_file, true]
|
|
860
|
+
else
|
|
861
|
+
raise "Unknown init_step: #{init_step}"
|
|
862
|
+
end
|
|
863
|
+
end
|
|
864
|
+
end
|
|
865
|
+
end
|
|
866
|
+
````
|
|
867
|
+
|
|
868
|
+
**呼び出し側(mk_semi_lattice.rb)も修正してください:**
|
|
869
|
+
|
|
870
|
+
````ruby
|
|
871
|
+
require_relative "mk_semi_lattice/manage_yaml" # ファイル名も変更した場合
|
|
872
|
+
|
|
873
|
+
# ...
|
|
874
|
+
selector = MkSemiLattice::ManageYaml.new(
|
|
875
|
+
parent_dir: $parent_dir,
|
|
876
|
+
semi_dir: semi_dir,
|
|
877
|
+
semi_lattice_yaml_path: semi_lattice_yaml_path,
|
|
878
|
+
options: options
|
|
879
|
+
)
|
|
880
|
+
init_file, init_step = selector.select_init_file_and_step
|
|
881
|
+
input_path, with_semi_lattice_yaml = selector.select_input_path_and_flag(init_file, init_step)
|
|
882
|
+
# ...
|
|
883
|
+
````
|
|
884
|
+
|
|
885
|
+
- クラス名を`SelectYaml`→`ManageYaml`に変更
|
|
886
|
+
- ファイル名もselect_yaml.rb→`manage_yaml.rb`に変更するのが推奨です(`require_relative`も合わせて修正)
|
|
887
|
+
|
|
888
|
+
この修正で意図通り動作します。
|
|
889
|
+
|
|
890
|
+
## User
|
|
891
|
+
def at_exit_action(app, semi_dir, parent_dir)をManageYamlに移動.
|
|
892
|
+
|
|
893
|
+
## Copilot
|
|
894
|
+
````ruby
|
|
895
|
+
# ...existing code...
|
|
896
|
+
|
|
897
|
+
# アプリ終了時の状態保存
|
|
898
|
+
def self.at_exit_action(app, semi_dir, parent_dir)
|
|
899
|
+
nodes_data = app.nodes.map do |n|
|
|
900
|
+
p [n.label, n.fixed, n.color]
|
|
901
|
+
{
|
|
902
|
+
id: app.node_table.key(n),
|
|
903
|
+
name: n.name,
|
|
904
|
+
type: n.type,
|
|
905
|
+
file_path: n.file_path,
|
|
906
|
+
x: n.x,
|
|
907
|
+
y: n.y,
|
|
908
|
+
color: n.color,
|
|
909
|
+
fixed: n.fixed
|
|
910
|
+
}
|
|
911
|
+
end
|
|
912
|
+
edges_data = app.edges.map do |e|
|
|
913
|
+
{
|
|
914
|
+
from: app.node_table.key(e.from),
|
|
915
|
+
to: app.node_table.key(e.to)
|
|
916
|
+
}
|
|
917
|
+
end
|
|
918
|
+
|
|
919
|
+
yaml_data = { nodes: nodes_data, edges: edges_data }
|
|
920
|
+
yaml_text = MkSemiLattice::MkNodeEdge.add_edge_comments(yaml_data)
|
|
921
|
+
if Dir.exist?(semi_dir)
|
|
922
|
+
File.write(File.join(semi_dir, "semi_lattice.yaml"), yaml_text)
|
|
923
|
+
else
|
|
924
|
+
File.write(File.join('.', "semi_lattice.yaml"), yaml_text)
|
|
925
|
+
end
|
|
926
|
+
Log.event("exited", parent_dir: parent_dir)
|
|
927
|
+
end
|
|
928
|
+
|
|
929
|
+
# ...existing code...
|
|
930
|
+
````
|
|
931
|
+
|
|
932
|
+
````ruby
|
|
933
|
+
# ...existing code...
|
|
934
|
+
|
|
935
|
+
# Ruby2Dには:closeイベントはありません。at_exitで保存処理を行います。
|
|
936
|
+
at_exit do
|
|
937
|
+
MkSemiLattice::ManageYaml.at_exit_action(app, semi_dir, $parent_dir)
|
|
938
|
+
end
|
|
939
|
+
|
|
940
|
+
# ...existing code...
|
|
941
|
+
````
|
|
942
|
+
|
|
943
|
+
- `at_exit_action`は`ManageYaml`の**クラスメソッド**として追加しました。
|
|
944
|
+
- `at_exit`ブロックでは`MkSemiLattice::ManageYaml.at_exit_action(...)`で呼び出してください。
|
|
945
|
+
- 元の`def at_exit_action ... end`は削除してください。
|
|
946
|
+
|
|
947
|
+
## User
|
|
948
|
+
それぞれの動作に対するactionをそれぞれの関数を作成し,それらをlib/ruby2d_action.rbに移動.
|
|
949
|
+
|
|
950
|
+
## Copilot
|
|
951
|
+
````ruby
|
|
952
|
+
# frozen_string_literal: true
|
|
953
|
+
|
|
954
|
+
module Ruby2dAction
|
|
955
|
+
def self.on_key_down(app, event)
|
|
956
|
+
app.shift_pressed = true if event.key.include?('shift')
|
|
957
|
+
end
|
|
958
|
+
|
|
959
|
+
def self.on_key_up(app, event)
|
|
960
|
+
app.shift_pressed = false if event.key.include?('shift')
|
|
961
|
+
end
|
|
962
|
+
|
|
963
|
+
def self.double_click?(clicked_node, last_click_node, last_click_time)
|
|
964
|
+
now = Time.now
|
|
965
|
+
if last_click_node == clicked_node && last_click_time && (now - last_click_time < 0.4)
|
|
966
|
+
return true, now
|
|
967
|
+
end
|
|
968
|
+
return false, now
|
|
969
|
+
end
|
|
970
|
+
|
|
971
|
+
def self.double_click_action(clicked_node, parent_dir)
|
|
972
|
+
comm = nil
|
|
973
|
+
if clicked_node.file_path
|
|
974
|
+
if File.directory?(clicked_node.file_path)
|
|
975
|
+
if RbConfig::CONFIG['host_os'] =~ /darwin/
|
|
976
|
+
comm = "open -a Terminal '#{clicked_node.file_path}'"
|
|
977
|
+
elsif RbConfig::CONFIG['host_os'] =~ /debian/
|
|
978
|
+
comm = "gnome-terminal --working-directory='#{clicked_node.file_path}'"
|
|
979
|
+
else
|
|
980
|
+
comm = "wt.exe -p Ubuntu-24.04 --colorScheme 'Tango Light' -d '#{clicked_node.file_path}'"
|
|
981
|
+
end
|
|
982
|
+
else
|
|
983
|
+
if RbConfig::CONFIG['host_os'] =~ /darwin/
|
|
984
|
+
comm = "open '#{clicked_node.file_path}'"
|
|
985
|
+
else
|
|
986
|
+
comm = "open '#{clicked_node.file_path}'"
|
|
987
|
+
end
|
|
988
|
+
end
|
|
989
|
+
puts comm
|
|
990
|
+
Log.event("open", target_dir: File.expand_path(clicked_node.file_path, parent_dir), parent_dir: parent_dir)
|
|
991
|
+
system comm
|
|
992
|
+
else
|
|
993
|
+
puts "no link error"
|
|
994
|
+
end
|
|
995
|
+
end
|
|
996
|
+
|
|
997
|
+
def self.on_mouse_down(app, event, last_click_node, last_click_time, parent_dir)
|
|
998
|
+
mx, my = event.x, event.y
|
|
999
|
+
shift_down = !!app.shift_pressed
|
|
1000
|
+
clicked_node = nil
|
|
1001
|
+
app.nodes.each do |n|
|
|
1002
|
+
if Math.hypot(n.x - mx, n.y - my) < 30
|
|
1003
|
+
clicked_node = n
|
|
1004
|
+
if shift_down
|
|
1005
|
+
n.fixed = false
|
|
1006
|
+
n.color = NODE_COLOR
|
|
1007
|
+
app.selected = nil
|
|
1008
|
+
else
|
|
1009
|
+
app.selected = n
|
|
1010
|
+
if event.button == :left
|
|
1011
|
+
n.fixed = true
|
|
1012
|
+
n.color = FIXED_COLOR
|
|
1013
|
+
end
|
|
1014
|
+
n.fixed = false if event.button == :middle
|
|
1015
|
+
n.linked = true if event.button == :right
|
|
1016
|
+
end
|
|
1017
|
+
end
|
|
1018
|
+
end
|
|
1019
|
+
|
|
1020
|
+
# ダブルクリック判定とファイルオープン
|
|
1021
|
+
if clicked_node
|
|
1022
|
+
is_double, now = double_click?(clicked_node, last_click_node, last_click_time)
|
|
1023
|
+
double_click_action(clicked_node, parent_dir) if is_double
|
|
1024
|
+
return clicked_node, now
|
|
1025
|
+
end
|
|
1026
|
+
[last_click_node, last_click_time]
|
|
1027
|
+
end
|
|
1028
|
+
|
|
1029
|
+
def self.on_mouse_up(app)
|
|
1030
|
+
app.selected = nil
|
|
1031
|
+
end
|
|
1032
|
+
|
|
1033
|
+
def self.on_mouse_move(app, event)
|
|
1034
|
+
if app.selected
|
|
1035
|
+
app.selected.x = event.x
|
|
1036
|
+
app.selected.y = event.y
|
|
1037
|
+
end
|
|
1038
|
+
end
|
|
1039
|
+
|
|
1040
|
+
def self.update_action(app)
|
|
1041
|
+
app.edges.each(&:relax)
|
|
1042
|
+
app.nodes.each { |n| n.relax(app.nodes) }
|
|
1043
|
+
app.nodes.each(&:update)
|
|
1044
|
+
app.edges.reverse.each(&:draw)
|
|
1045
|
+
app.nodes.reverse.each do |n|
|
|
1046
|
+
n.draw(app.selected == n)
|
|
1047
|
+
end
|
|
1048
|
+
end
|
|
1049
|
+
end
|
|
1050
|
+
````
|
|
1051
|
+
|
|
1052
|
+
**mk_semi_lattice.rb 側の修正例:**
|
|
1053
|
+
|
|
1054
|
+
````ruby
|
|
1055
|
+
require_relative "ruby2d_action"
|
|
1056
|
+
# ...existing code...
|
|
1057
|
+
|
|
1058
|
+
last_click_time = nil
|
|
1059
|
+
last_click_node = nil
|
|
1060
|
+
|
|
1061
|
+
on :key_down do |event|
|
|
1062
|
+
Ruby2dAction.on_key_down(app, event)
|
|
1063
|
+
end
|
|
1064
|
+
|
|
1065
|
+
on :key_up do |event|
|
|
1066
|
+
Ruby2dAction.on_key_up(app, event)
|
|
1067
|
+
end
|
|
1068
|
+
|
|
1069
|
+
on :mouse_down do |event|
|
|
1070
|
+
clicked_node, last_time = Ruby2dAction.on_mouse_down(app, event, last_click_node, last_click_time, $parent_dir)
|
|
1071
|
+
last_click_node = clicked_node
|
|
1072
|
+
last_click_time = last_time
|
|
1073
|
+
end
|
|
1074
|
+
|
|
1075
|
+
on :mouse_up do
|
|
1076
|
+
Ruby2dAction.on_mouse_up(app)
|
|
1077
|
+
end
|
|
1078
|
+
|
|
1079
|
+
on :mouse_move do |event|
|
|
1080
|
+
Ruby2dAction.on_mouse_move(app, event)
|
|
1081
|
+
end
|
|
1082
|
+
|
|
1083
|
+
update do
|
|
1084
|
+
Ruby2dAction.update_action(app)
|
|
1085
|
+
end
|
|
1086
|
+
````
|
|
1087
|
+
|
|
1088
|
+
- それぞれのRuby2Dイベントの処理を`Ruby2dAction`モジュールの関数に分離しました。
|
|
1089
|
+
- `last_click_node`と`last_click_time`の更新も`on_mouse_down`の返り値で管理できます。
|
|
1090
|
+
- これでmk_semi_lattice.rbがすっきりし、イベントごとの処理が明確になります。
|