python_uml_class 0.1.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.
@@ -0,0 +1,352 @@
1
+ require "tempfile"
2
+ require "facter"
3
+
4
+ CStruct = Struct.new(:type,
5
+ :file_name,
6
+ :name,
7
+ :block_count,
8
+ :var_list,
9
+ :method_list,
10
+ :inherit_list,
11
+ :composition_list)
12
+
13
+ def get_formatter_path
14
+ return @config["formatter_path"] if @config["formatter_path"].to_s != ""
15
+
16
+ ""
17
+ end
18
+
19
+ def print_uml(out, out_list)
20
+ out_list.each do |o_list|
21
+ if o_list.type == :class_start
22
+ # nop
23
+ elsif o_list.type == :module_start
24
+ out.push "namespace \"#{o_list.name}\" {"
25
+ elsif o_list.type == :class_end
26
+ pp o_list if o_list.name == ""
27
+ out.push "class \"#{o_list.name}\" {"
28
+ # インスタンス変数の出力
29
+ o_list.var_list.uniq.each do |iv|
30
+ out.push iv
31
+ end
32
+ # メソッドの出力
33
+ o_list.method_list.each do |ml|
34
+ out.push ml
35
+ end
36
+ out.push "}"
37
+ # 継承リストの出力
38
+ o_list.inherit_list.each do |ih|
39
+ out.push "\"#{o_list.name}\" -[##{@config["inherit_color"]}]-|> \"#{ih}\""
40
+ end
41
+ # compo
42
+ o_list.composition_list.uniq.each do |co|
43
+ out.push "\"#{o_list.name}\" *-[##{@config["composition_color"]}]- \"#{co}\""
44
+ end
45
+ elsif o_list.type == :module_end
46
+ # インスタンス変数がある場合はモジュール名と同じクラスを定義
47
+ if o_list.var_list.size != 0 or
48
+ o_list.method_list.size != 0 or
49
+ o_list.inherit_list.size != 0 or
50
+ o_list.composition_list.size != 0
51
+ pp o_list if o_list.name == ""
52
+ out.push "class #{o_list.name} {"
53
+ # インスタンス変数の出力
54
+ o_list.var_list.uniq.each do |iv|
55
+ out.push iv
56
+ end
57
+ # メソッドの出力
58
+ o_list.method_list.each do |ml|
59
+ out.push ml
60
+ end
61
+ out.push "}"
62
+ # 継承リストの出力
63
+ o_list.inherit_list.each do |ih|
64
+ out.push "\"#{o_list.name}\" -[##{@config["inherit_color"]}]-|> \"#{ih}\""
65
+ end
66
+ # compo
67
+ o_list.composition_list.uniq.each do |co|
68
+ out.push "\"#{o_list.name}\" *-[##{@config["composition_color"]}]- \"#{co}\""
69
+ end
70
+ end
71
+ out.push "}"
72
+ else
73
+ # error
74
+ puts "error!"
75
+ end
76
+ end
77
+ out
78
+ end
79
+
80
+ def create_uml_class(in_dir, _out_file)
81
+ out = []
82
+ out.push "@startuml"
83
+
84
+ puts "in_dir = #{in_dir}"
85
+ global_var = []
86
+ out_list = []
87
+ def_list = []
88
+ import_list = []
89
+
90
+ Dir.glob("#{in_dir}/**/*.py") do |f|
91
+ import_list.push File.basename(f).split(".")[0]
92
+ end
93
+
94
+ Dir.glob("#{in_dir}/**/*.py") do |f|
95
+ puts f
96
+ puts @config["exclude_path"]
97
+ if @config["exclude_path"] != ""
98
+ if f =~ Regexp.new(@config["exclude_path"])
99
+ puts "skip #{f}"
100
+ next
101
+ end
102
+ end
103
+ buf = ""
104
+ file_name = File.basename(f).split(".")[0]
105
+ Tempfile.create("pylint") do |tmp_file|
106
+ # FileUtils.cp(f, tmp_file.path)
107
+ kernel = Facter.value(:kernel)
108
+ if kernel == "windows"
109
+ open("|#{get_formatter_path} #{f} > #{tmp_file.path}") do |ff|
110
+ if ff.read.to_s != ""
111
+ puts "pylint error #{ff}"
112
+ return
113
+ else
114
+ buf = File.binread tmp_file.path
115
+ end
116
+ end
117
+ else
118
+ open("|#{get_formatter_path} #{f} > #{tmp_file.path}") do |ff|
119
+ puts "|#{get_formatter_path} #{f} > #{tmp_file.path}"
120
+ if ff.read.to_s != ""
121
+ puts "pylint error #{ff}"
122
+ return
123
+ else
124
+ buf = File.binread tmp_file.path
125
+ end
126
+ end
127
+ end
128
+ end
129
+
130
+ cstruct_list = []
131
+ block_count = 0
132
+ method_type = :public
133
+ class_name = ""
134
+ file_struct_list = []
135
+ file_struct_list.push CStruct.new(:class_start, file_name, file_name + ".global", block_count, [], [], [], [])
136
+ file_struct_list.push CStruct.new(:class_end, file_name, file_name + ".global", block_count, [], [], [], [])
137
+ is_def = false
138
+
139
+ # ソースを解析
140
+ buf.each_line do |line|
141
+ next if line =~ /^[\r\n]*$/ # 空行は対象外
142
+
143
+ line.chomp!
144
+ # ブロックの開始/終了
145
+ indent_num = line.match(/^ +/).to_s.size / 4
146
+ puts "block_count=#{indent_num} cstruct_size=#{cstruct_list.size} is_def=#{is_def} #{line}"
147
+ if block_count == indent_num
148
+ # 変化なし
149
+ elsif block_count > indent_num
150
+ # ブロックの終了
151
+ block_count = indent_num
152
+ # 関数の終了
153
+ if is_def == true and def_list[-1].block_count >= block_count
154
+ is_def = false
155
+ method_type = :public
156
+ end
157
+ # クラスの終了
158
+ if cstruct_list.size != 0 && cstruct_list[-1].block_count >= block_count # block_countが一致
159
+ puts "end of #{cstruct_list[-1].name}"
160
+ out_list.push cstruct_list[-1]
161
+ cstruct_list.slice!(-1) # 最後の要素を削除
162
+ method_type = :public
163
+ end
164
+ else
165
+ # ブロックの開始
166
+ block_count = indent_num
167
+ end
168
+ #puts "block_count=#{indent_num} class_count=#{cstruct_list.size} def_count=#{def_list.size} #{line}"
169
+
170
+ # method_type
171
+ if line =~ /@staticmethod/
172
+ method_type = :private
173
+ end
174
+
175
+ # import
176
+ line.match(/import \S+/) do |m|
177
+ import_name = m.to_s.gsub(/import /, "")
178
+ if 0 != import_list.select { |im| im == import_name }.size and file_name != import_name
179
+ if cstruct_list.size != 0
180
+ cstruct_list[-1].composition_list.push import_name
181
+ else
182
+ file_struct_list[-1].composition_list.push import_name
183
+ end
184
+ end
185
+ end
186
+
187
+ # クラスの開始
188
+ if line =~ /^\s*class.*:/
189
+ work = line.gsub(/class\s/, "")
190
+ class_name = work.split("\(")[0].to_s.gsub(/:/, "")
191
+ base_name = work.match(/\(.*\)/).to_s.gsub(/[()]/, "")
192
+ class_name = "#{file_name}.#{class_name}"
193
+ puts "class_name=#{class_name}"
194
+ puts "base_name=#{base_name}"
195
+ out_list.push CStruct.new(:class_start, file_name, class_name, block_count, [], [], [], [])
196
+ cstruct_list.push CStruct.new(:class_end, file_name, class_name, block_count, [], [], [], [])
197
+ # pp line if class_name == ""
198
+ if base_name != ""
199
+ if base_name =~ /,/
200
+ base_name.split(",").each do |name|
201
+ cstruct_list[-1].inherit_list.push name
202
+ end
203
+ else
204
+ cstruct_list[-1].inherit_list.push base_name
205
+ end
206
+ end
207
+ next
208
+ end
209
+
210
+ if line =~ /^\s*private$/
211
+ method_type = :private
212
+ elsif line =~ /^\s*protected$/
213
+ method_type = :protected
214
+ elsif line =~ /^\s*public$/
215
+ method_type = :public
216
+ end
217
+
218
+ if line =~ /^\s*def\s/
219
+ # 関数名を取り出す
220
+ method = line.chomp.gsub(/\s*def\s*/, "")
221
+ unless method =~ /\(/
222
+ # 関数名にカッコをつける
223
+ sp = method.split(" ")
224
+ method = if sp.size > 1
225
+ sp[0].to_s + "(" + sp[1..-1].to_s + ")"
226
+ else
227
+ method + "()"
228
+ end
229
+ end
230
+ if cstruct_list.size != 0
231
+ method_list = cstruct_list[-1].method_list
232
+ case method_type
233
+ when :public
234
+ method_list.push "+ #{method}"
235
+ when :private
236
+ method_list.push "- #{method}"
237
+ when :protected
238
+ method_list.push "# #{method}"
239
+ end
240
+ else
241
+ method_list = file_struct_list[-1].method_list
242
+ method_list.push "+ #{method}"
243
+ end
244
+ def_list.push CStruct.new(:method_start, file_name, method, block_count, [], [], [], [])
245
+ is_def = true
246
+ end
247
+
248
+ # composition_list
249
+ # クラスの呼び出し箇所
250
+ line.match(/\s([A-Z][a-zA-Z]+)\.[a-z]/) do |m|
251
+ c_name = m.to_s.split(".")[0].gsub(/ /, "")
252
+ puts "compo c_name=#{c_name}"
253
+ if cstruct_list.size != 0
254
+ cstruct_list[-1].composition_list.push c_name
255
+ else
256
+ file_struct_list[-1].composition_list.push c_name
257
+ end
258
+ end
259
+
260
+ # クラスの初期化箇所
261
+ line.match(/[\s\.][A-Z][A-Za-z]+\(/) do |m|
262
+ c_name = m.to_s.gsub(/\(/, "").gsub(/[\s\.]/, "")
263
+ puts "compo c_name=#{c_name}"
264
+ if cstruct_list.size != 0
265
+ cstruct_list[-1].composition_list.push c_name
266
+ else
267
+ file_struct_list[-1].composition_list.push c_name
268
+ end
269
+ end
270
+
271
+ # インスタンス変数
272
+ if line =~ /^\s*self\.[a-zA-Z0-9_]+\s+=/ and cstruct_list.size != 0
273
+ line.match(/self\.[a-zA-Z0-9_]+/) do |m|
274
+ instance_var = cstruct_list[-1].var_list
275
+ val = m.to_s.gsub(/self\./, "")
276
+ case method_type
277
+ when :public
278
+ instance_var.push "+ #{val}"
279
+ when :private
280
+ instance_var.push "- #{val}"
281
+ when :protected
282
+ instance_var.push "# #{val}"
283
+ end
284
+ end
285
+ end
286
+
287
+ # クラス変数
288
+ if line =~ /^\s*[a-zA-Z0-9_]+\s+=/ and cstruct_list.size != 0 and is_def == false
289
+ line.match(/[a-zA-Z0-9_]+/) do |m|
290
+ instance_var = cstruct_list[-1].var_list
291
+ val = m.to_s
292
+ instance_var.push "- #{val}"
293
+ end
294
+ end
295
+
296
+ # 外部変数
297
+ if line =~ /^\s*[a-zA-Z0-9_]+\s+=/ and cstruct_list.size == 0 and is_def == false
298
+ line.match(/\$*[a-zA-Z0-9_]+/) do |m|
299
+ file_struct_list[-1].var_list.push "+ #{m}"
300
+ end
301
+ end
302
+ end
303
+
304
+ # ファイルの終了
305
+ if block_count != 0
306
+ puts "endf of #{f}"
307
+ # クラスの終了
308
+ if cstruct_list.size != 0
309
+ puts "end of #{cstruct_list[-1].name}"
310
+ out_list.push cstruct_list[-1]
311
+ cstruct_list.slice!(-1) # 最後の要素を削除
312
+ end
313
+ file_struct_list.each do |fs|
314
+ out_list.push fs
315
+ end
316
+ end
317
+ end
318
+
319
+ # 継承リストとコンポジションリストのチュエック
320
+ out_list.each_index do |i|
321
+ out_list[i].composition_list.each_index do |j|
322
+ # compo_nameがfile_name.class_nameに変更可能かチェック
323
+ compo_name = out_list[i].composition_list[j]
324
+ out_list.select { |a| a.name.split(".")[-1] == compo_name }.each do |m|
325
+ puts "m=#{m.name}"
326
+ out_list[i].composition_list[j] = m.name
327
+ end
328
+ def_list.each do |def_struct|
329
+ # comp_nameが自分で定義した関数名の場合は削除
330
+ #puts "#{compo_name} == #{def_struct.name.split("(")[0]}"
331
+ if compo_name == def_struct.name.split("(")[0]
332
+ puts "match_def #{compo_name} == #{def_struct.name.split("(")[0]}"
333
+ out_list[i].composition_list.delete_at(j)
334
+ end
335
+ end
336
+ end
337
+ out_list[i].inherit_list.each_index do |j|
338
+ # compo_nameがfile_name.class_nameに変更可能かチェック
339
+ inherit_name = out_list[i].inherit_list[j]
340
+ out_list.select { |a| a.name.split(".")[-1] == inherit_name }.each do |m|
341
+ puts "m=#{m.name}"
342
+ out_list[i].inherit_list[j] = m.name
343
+ end
344
+ end
345
+ end
346
+
347
+ # UMLの出力
348
+ out = print_uml(out, out_list)
349
+
350
+ out.push "@enduml"
351
+ out.join("\n")
352
+ end
data/lib/css/index.css ADDED
@@ -0,0 +1,178 @@
1
+ body {
2
+ color: #000000;
3
+ background-color: #cac3ec4f;
4
+ overflow: hidden;
5
+ font-size: 12px;
6
+ }
7
+
8
+ hr {
9
+ color: #ffffff;
10
+ background-color: #000000;
11
+ height: 1px;
12
+ /* 線の太さ */
13
+ border: 1px;
14
+ /* 枠の太さ */
15
+ border-style: solid;
16
+ /* 枠の種類 */
17
+ }
18
+
19
+ .error {
20
+ color: red;
21
+ }
22
+
23
+ .outarea {
24
+ background-color: #FFFFFF;
25
+ margin: 5px;
26
+ padding: 5px;
27
+ width: 95vw;
28
+ height: 50vh;
29
+ overflow: auto;
30
+ }
31
+
32
+ .inarea {
33
+ border: thin solid #000000;
34
+ margin: 5px;
35
+ padding: 5px;
36
+ width: 98%;
37
+ }
38
+
39
+ input.long {
40
+ width: 98%;
41
+ background-color: #FAFAFA;
42
+ margin: 5px;
43
+ padding: 5px;
44
+ }
45
+
46
+ textarea.long {
47
+ width: 95vw;
48
+ height: 50vh;
49
+ }
50
+
51
+ .ui-widget {
52
+ font-size: 12px;
53
+ }
54
+
55
+ .ui-autocomplete {
56
+ max-height: 45vh;
57
+ max-width: 90wh;
58
+ overflow-y: auto;
59
+ overflow-x: auto;
60
+ padding-right: 10px;
61
+ }
62
+
63
+ #jquery-ui-autocomplete label {
64
+ float: left;
65
+ margin-right: 0.5em;
66
+ color: black;
67
+ }
68
+
69
+ .ui-autocomplete.ui-front {
70
+ max-height: 250px;
71
+ overflow-y: auto;
72
+ /* prevent horizontal scrollbar */
73
+ overflow-x: hidden;
74
+ /* add padding to account for vertical scrollbar */
75
+ z-index: 1000 !important;
76
+ }
77
+
78
+ .ui-dialog {
79
+ position: absolute;
80
+ top: 0;
81
+ left: 0;
82
+ padding: .2em;
83
+ outline: 0;
84
+ }
85
+
86
+ .long {
87
+ width: 90%;
88
+ }
89
+
90
+ #setting_dialog {
91
+ color: #ffffff;
92
+ background-color: #000000;
93
+ }
94
+
95
+ .setting_name {
96
+ width: 200px;
97
+ color: #ffffff;
98
+ background-color: #000000;
99
+ }
100
+
101
+ .setting_value {
102
+ width: 300px;
103
+ color: #ffffff;
104
+ background-color: #000000;
105
+ }
106
+
107
+ .setting_checkbox {
108
+ color: #ffffff;
109
+ background-color: #000000;
110
+ }
111
+
112
+ ul.log {
113
+ list-style-type: none;
114
+ font-size: 12px;
115
+ color: #000000;
116
+ }
117
+
118
+ input[type="search"] {
119
+ -webkit-appearance: searchfield;
120
+ }
121
+
122
+ input[type="search"]::-webkit-search-cancel-button {
123
+ -webkit-appearance: searchfield-cancel-button;
124
+ }
125
+
126
+ /* menu */
127
+ .menu {
128
+ display: flex;
129
+ justify-content: flex-start;
130
+ list-style-type: none;
131
+ color: #393737;
132
+ padding: 0;
133
+ font-size: 12px;
134
+ font-weight: bold;
135
+ }
136
+
137
+ .menu li {
138
+ position: relative;
139
+ width: 100px;
140
+ margin-left: 1px;
141
+ padding: 5px;
142
+ background: #d8dada;
143
+ list-style-type: none;
144
+ }
145
+
146
+ .menu li a {
147
+ color: rgb(20, 114, 192);
148
+ }
149
+
150
+ .menu li a:hover {
151
+ background: #eba399;
152
+ }
153
+
154
+ .menuSub {
155
+ position: absolute;
156
+ margin-left: -6px;
157
+ padding: 0;
158
+ display: none;
159
+ }
160
+
161
+ /*.openが付与された時、表示の設定*/
162
+ .menuSub.open {
163
+ display: block;
164
+ }
165
+
166
+ .menuSub li a {
167
+ padding: 5px;
168
+ margin-left: -5px;
169
+ margin-right: -5px;
170
+ margin-bottom: -5px;
171
+ display: block;
172
+ color: rgb(20, 114, 192);
173
+ text-decoration: none;
174
+ }
175
+
176
+ .menuSub li a:hover {
177
+ background: #eba399;
178
+ }
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env python3
2
+
3
+ import sys
4
+ import ast
5
+ import astor
6
+ import pprint
7
+
8
+ def remove_comments_from_code(code):
9
+ # コードをASTに変換
10
+ tree = ast.parse(code)
11
+
12
+ #print("----------")
13
+ #print(ast.dump(tree, indent=4))
14
+ #print("----------")
15
+
16
+ # ASTを操作してコメントを削除
17
+ for node in ast.walk(tree):
18
+
19
+ #print(vars(node))
20
+ #print("--------------------------------------------------")
21
+ #pprint.pprint(vars(node))
22
+ if isinstance(node, ast.Expr) and isinstance(node.value, ast.Str) and isinstance(node.value.s, str):
23
+ # 文字列としてコメントが格納されているExprノードを削除
24
+ if node.value.s.startswith(("#", '"""', "'''")):
25
+ node.value.s = "" # コメントを空文字列に設定
26
+
27
+ # ASTからコードに変換
28
+ modified_code = astor.to_source(tree)
29
+
30
+ return modified_code
31
+
32
+ if __name__ == "__main__":
33
+ file = sys.argv[1]
34
+ f = open(file, "r")
35
+ code_without_comments = remove_comments_from_code(f.read())
36
+ print(code_without_comments)
@@ -0,0 +1,80 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+
4
+ <head>
5
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
6
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
7
+ <title>PythonUMLClass</title>
8
+ <!-- jQuery -->
9
+ <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
10
+ <!-- jQuery UI -->
11
+ <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
12
+ <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css">
13
+
14
+ <script src="js/main.js"></script>
15
+ <link rel="stylesheet" href="css/index.css" type="text/css">
16
+ </head>
17
+
18
+ <body>
19
+ <div id="msg_dialog" style="display:none;">
20
+ <div id="msg_text">message</div>
21
+ </div>
22
+ <hr>
23
+ <!-- menu -->
24
+ <div id="setting_dialog" style="display:none;">
25
+ <dl id="wrap"></dl>
26
+ </div>
27
+ <div>
28
+ <ul class="menu">
29
+ <Li><a href="#" id="exec" name="exec">実行</a></li>
30
+ <li><a href="#" id="stop" name="stop">停止</a></li>
31
+ <li>
32
+ 設定
33
+ <ul class="menuSub">
34
+ <li><a href="#" id="setting">設定</a></li>
35
+ <li><a href="#" id="save_setting">設定保存</a></li>
36
+ <li><a href="#" id="load_setting">設定読み込み</a></li>
37
+ </ul>
38
+ </li>
39
+ <!--
40
+ <li>
41
+ menu3
42
+ <ul class="menuSub">
43
+ <li><a href="#">menu3-1</a></li>
44
+ <li><a href="#">menu3-2</a></li>
45
+ </ul>
46
+ </li>
47
+ -->
48
+ </ul>
49
+ </div>
50
+
51
+ <table>
52
+ <tr>
53
+ <td>
54
+ <div id="dialog1" style="display:none;">
55
+ <input class="inarea" type="search" name="search_str" id="search_str">
56
+ </div>
57
+ </td>
58
+ <td class="long"><input class="inarea" type="search" id="inDir" name="inDir"></td>
59
+ <td><input type="button" id="select_dir" value="対象フォルダ" /></td>
60
+ </tr>
61
+ <tr>
62
+ <td>
63
+ <div id="dialog2" style="display:none;">
64
+ <input class="inarea" type="search" name="search_str2" id="search_str2">
65
+ </div>
66
+ </td>
67
+ <td class="long"><input class="inarea" type="search" id="outFile" name="outFile"></td>
68
+ <td><input type="button" id="select_file" value="出力ファイル" /></td>
69
+ <td><input type="button" id="open_file" value="開く" /></td>
70
+ </tr>
71
+ </table>
72
+
73
+ <div class="outarea">
74
+ <ul name="log" id="log" class="log">
75
+ </ul>
76
+ </div>
77
+
78
+ </body>
79
+
80
+ </html>