ruby_uml_class 0.2.0 → 0.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.
@@ -1,297 +1,322 @@
1
- require "tempfile"
2
-
3
- CStruct = Struct.new(:type,
4
- :name,
5
- :block_count,
6
- :var_list,
7
- :method_list,
8
- :inherit_list,
9
- :composition_list)
10
-
11
- def print_uml(out, out_list)
12
- out_list.each do |o_list|
13
- if o_list.type == :class_start
14
- # nop
15
- elsif o_list.type == :module_start
16
- out.push "namespace #{o_list.name} {"
17
- elsif o_list.type == :class_end
18
- pp o_list if o_list.name == ""
19
- out.push "class #{o_list.name} {"
20
- # インスタンス変数の出力
21
- o_list.var_list.uniq.each do |iv|
22
- out.push iv
23
- end
24
- # メソッドの出力
25
- o_list.method_list.each do |ml|
26
- out.push ml
27
- end
28
- out.push "}"
29
- # 継承リストの出力
30
- o_list.inherit_list.each do |ih|
31
- out.push "#{o_list.name} --|> #{ih}"
32
- end
33
- # compo
34
- o_list.composition_list.uniq.each do |co|
35
- out.push "#{o_list.name} *-- #{co}"
36
- end
37
- elsif o_list.type == :module_end
38
- # インスタンス変数がある場合はモジュール名と同じクラスを定義
39
- if o_list.var_list.size != 0 or
40
- o_list.method_list.size != 0 or
41
- o_list.inherit_list.size != 0 or
42
- o_list.composition_list.size != 0
43
- pp o_list if o_list.name == ""
44
- out.push "class #{o_list.name} {"
45
- # インスタンス変数の出力
46
- o_list.var_list.uniq.each do |iv|
47
- out.push iv
48
- end
49
- # メソッドの出力
50
- o_list.method_list.each do |ml|
51
- out.push ml
52
- end
53
- out.push "}"
54
- # 継承リストの出力
55
- o_list.inherit_list.each do |ih|
56
- out.push "#{o_list.name} --|> #{ih}"
57
- end
58
- # compo
59
- o_list.composition_list.uniq.each do |co|
60
- out.push "#{o_list.name} *-- #{co}"
61
- end
62
- end
63
- out.push "}"
64
- else
65
- # error
66
- puts "error!"
67
- end
68
- end
69
- return out
70
- end
71
-
72
- def delete_here_doc(buf)
73
- new_buf = []
74
- here_doc = false
75
- here_word = ""
76
- buf.each_line do |line|
77
- if line =~ /(<<|<<~|<<-)[A-Z]+/
78
- here_doc = true
79
- here_word = line.match(/(<<|<<~|<<-)[A-Z]+/).to_s.gsub(/[<~-]/, "")
80
- end
81
- if here_word != "" and line =~ Regexp.new("^\s*#{here_word}$")
82
- here_word = ""
83
- here_doc = false
84
- pp line
85
- end
86
- if here_doc == false
87
- new_buf.push line
88
- else
89
- pp line
90
- end
91
- end
92
- return new_buf.join("")
93
- end
94
-
95
- def create_uml_class(in_dir, out_file)
96
- out = []
97
- out.push "@startuml"
98
-
99
- puts "in_dir = #{in_dir}"
100
- main_composition_list = []
101
- main_method_list = []
102
- global_var = []
103
-
104
- Dir.glob("#{in_dir}/**/*.{rb,ru}") do |f|
105
- puts f
106
- buf = ""
107
- Tempfile.create("rufo") do |tmp_file|
108
- FileUtils.cp(f, tmp_file.path)
109
- open("|rufo #{tmp_file.path}") do |f|
110
- if f.read =~ /error/
111
- puts "rufo error #{f}"
112
- return
113
- else
114
- buf = File.binread tmp_file.path
115
- end
116
- end
117
- end
118
-
119
- # コメント削除
120
- buf.gsub!(/(([\/\"\'].*?[\/\"\'])|([^\/\"\'\)\s]*#.+?$))/) do |m|
121
- if m[0] == "#" and m[0] != "{"
122
- #puts "comment #{m}"
123
- # コメント
124
- ""
125
- else
126
- #puts "not comment #{m}"
127
- # コメント以外
128
- m
129
- end
130
- end
131
- # ヒアドキュメント削除
132
- buf = delete_here_doc(buf)
133
-
134
- out_list = []
135
- cstruct_list = []
136
- block_count = 0
137
- method_type = :public
138
- class_name = ""
139
- # ソースを解析
140
- buf.each_line do |line|
141
- next if line =~ /^[\r\n]*$/ # 空行は対象外
142
-
143
- # ブロックの開始/終了
144
- indent_num = line.match(/^[ ]+/).to_s.size / 2
145
- if block_count == indent_num
146
- # 変化なし
147
- elsif block_count > indent_num
148
- # ブロックの終了
149
- block_count = indent_num
150
- else
151
- # ブロックの開始
152
- block_count = indent_num
153
- end
154
-
155
- #line.gsub!(/\".+\"/, "\"delete_string\"") # 文字列を削除
156
- if line =~ /^\s*class\s/
157
- unless line =~ /<</ # 特異クラスではない
158
- work = line.gsub(/class\s/, "")
159
- class_name = work.split("<")[0].to_s.chomp.match(/[A-Z][A-Za-z0-9_:]+/).to_s
160
- base_name = work.split("<")[1].to_s.chomp.match(/[A-Z][A-Za-z0-9_:]+/).to_s
161
- class_name.gsub!(/::/, ".")
162
- if out_list.size != 0 and out_list[-1].type == :class_start # classが連続している
163
- class_name = out_list[-1].name + "." + class_name
164
- out_list[-1].name = class_name
165
- cstruct_list[-1].name = class_name
166
- else
167
- out_list.push CStruct.new(:class_start, class_name, block_count, [], [], [], [])
168
- cstruct_list.push CStruct.new(:class_end, class_name, block_count, [], [], [], [])
169
- end
170
- #pp line if class_name == ""
171
- if base_name != ""
172
- #base_name.gsub!(/::/, ".")
173
- cstruct_list[-1].inherit_list.push base_name
174
- end
175
- end
176
- next unless line =~ /end\s*$/ # 1行で終了しない場合
177
- elsif line =~ /^\s*module\s/
178
- module_name = line.split(" ")[1].to_s.chomp
179
- module_name.gsub!(/^[:]+/, "")
180
- module_name.gsub!(/::/, ".")
181
- out_list.push CStruct.new(:module_start, module_name, block_count, [], [], [], [])
182
- cstruct_list.push CStruct.new(:module_end, module_name, block_count, [], [], [], [])
183
- next unless line =~ /end\s*$/ # 1行で終了しない場合
184
- end
185
-
186
- if line =~ /^\s*private$/
187
- method_type = :private
188
- elsif line =~ /^\s*protected$/
189
- method_type = :protected
190
- elsif line =~ /^\s*public$/
191
- method_type = :public
192
- end
193
-
194
- if line =~ /^\s*def\s/
195
- # 関数名を取り出す
196
- method = line.chomp.gsub(/\s*def\s*/, "")
197
- unless method =~ /\(/
198
- # 関数名にカッコをつける
199
- sp = method.split(" ")
200
- if sp.size > 1
201
- method = sp[0].to_s + "(" + sp[1..-1].to_s + ")"
202
- else
203
- method = method + "()"
204
- end
205
- end
206
- if cstruct_list.size != 0
207
- method_list = cstruct_list[-1].method_list
208
- case method_type
209
- when :public
210
- method_list.push "+ #{method}"
211
- when :private
212
- method_list.push "- #{method}"
213
- when :protected
214
- method_list.push "# #{method}"
215
- end
216
- else
217
- main_method_list.push "+ #{method}"
218
- end
219
- end
220
-
221
- # composition_list
222
- line.match(/(([\/\"\')].*?\.new.*?[\/\"\'])|(?![\/\"\'])([a-zA-Z0-9_]+\.new))/) do |m|
223
- if m.to_s[0] != "/" and m.to_s[0] != "\"" and m.to_s[0] != "'"
224
- name = m.to_s.gsub(/\.new/, "").match(/[A-Z][A-Za-z0-9_]+/).to_s
225
- if name != ""
226
- if cstruct_list.size != 0
227
- cstruct_list[-1].composition_list.push name
228
- else
229
- main_composition_list.push "main *-- #{name}"
230
- end
231
- end
232
- end
233
- end
234
-
235
- # インスタンス変数
236
- if line =~ /\s*@\S+/
237
- if cstruct_list.size != 0
238
- line.match(/@[a-zA-Z0-9_]+/) { |m|
239
- instance_var = cstruct_list[-1].var_list
240
- val = m.to_s.gsub(/@/, "")
241
- case method_type
242
- when :public
243
- instance_var.push "+ #{val}"
244
- when :private
245
- instance_var.push "- #{val}"
246
- when :protected
247
- instance_var.push "# #{val}"
248
- end
249
- }
250
- end
251
- end
252
-
253
- # 外部変数
254
- line.match(/\$[a-zA-Z0-9_]+/) { |m|
255
- global_var.push "+ #{m.to_s}"
256
- }
257
-
258
- # クラスの終了
259
- if cstruct_list.size != 0
260
- if block_count == cstruct_list[-1].block_count # block_countが一致
261
- #puts "end of #{cstruct_list[-1].name}"
262
- out_list.push cstruct_list[-1]
263
- cstruct_list.slice!(-1) # 最後の要素を削除
264
- end
265
- end
266
- #puts "#{block_count} #{line.chomp}"
267
- end
268
- if block_count != 0
269
- # エラー
270
- puts f
271
- return ""
272
- end
273
-
274
- # UMLの出力
275
- out = print_uml(out, out_list)
276
- end
277
-
278
- if main_method_list.size != 0 or
279
- main_composition_list.size != 0 or
280
- main_method_list.size != 0
281
- out.push "class main {"
282
- main_method_list.each do |mml|
283
- out.push mml
284
- end
285
- # グローバル変数の出力
286
- global_var.uniq.each do |gv|
287
- out.push gv
288
- end
289
- out.push "}"
290
- main_composition_list.uniq.each do |mcl|
291
- out.push mcl
292
- end
293
- end
294
-
295
- out.push "@enduml"
296
- return out.join("\n")
297
- end
1
+ require "tempfile"
2
+ require "facter"
3
+
4
+ CStruct = Struct.new(:type,
5
+ :name,
6
+ :block_count,
7
+ :var_list,
8
+ :method_list,
9
+ :inherit_list,
10
+ :composition_list)
11
+
12
+ def get_rufo_path
13
+ ENV["PATH"].split(";").each do |path|
14
+ rufo_path = "#{path}\\rufo"
15
+ if File.exists? rufo_path
16
+ return rufo_path
17
+ end
18
+ end
19
+ return ""
20
+ end
21
+
22
+ def print_uml(out, out_list)
23
+ out_list.each do |o_list|
24
+ if o_list.type == :class_start
25
+ # nop
26
+ elsif o_list.type == :module_start
27
+ out.push "namespace #{o_list.name} {"
28
+ elsif o_list.type == :class_end
29
+ pp o_list if o_list.name == ""
30
+ out.push "class #{o_list.name} {"
31
+ # インスタンス変数の出力
32
+ o_list.var_list.uniq.each do |iv|
33
+ out.push iv
34
+ end
35
+ # メソッドの出力
36
+ o_list.method_list.each do |ml|
37
+ out.push ml
38
+ end
39
+ out.push "}"
40
+ # 継承リストの出力
41
+ o_list.inherit_list.each do |ih|
42
+ out.push "#{o_list.name} --|> #{ih}"
43
+ end
44
+ # compo
45
+ o_list.composition_list.uniq.each do |co|
46
+ out.push "#{o_list.name} *-- #{co}"
47
+ end
48
+ elsif o_list.type == :module_end
49
+ # インスタンス変数がある場合はモジュール名と同じクラスを定義
50
+ if o_list.var_list.size != 0 or
51
+ o_list.method_list.size != 0 or
52
+ o_list.inherit_list.size != 0 or
53
+ o_list.composition_list.size != 0
54
+ pp o_list if o_list.name == ""
55
+ out.push "class #{o_list.name} {"
56
+ # インスタンス変数の出力
57
+ o_list.var_list.uniq.each do |iv|
58
+ out.push iv
59
+ end
60
+ # メソッドの出力
61
+ o_list.method_list.each do |ml|
62
+ out.push ml
63
+ end
64
+ out.push "}"
65
+ # 継承リストの出力
66
+ o_list.inherit_list.each do |ih|
67
+ out.push "#{o_list.name} --|> #{ih}"
68
+ end
69
+ # compo
70
+ o_list.composition_list.uniq.each do |co|
71
+ out.push "#{o_list.name} *-- #{co}"
72
+ end
73
+ end
74
+ out.push "}"
75
+ else
76
+ # error
77
+ puts "error!"
78
+ end
79
+ end
80
+ return out
81
+ end
82
+
83
+ def delete_here_doc(buf)
84
+ new_buf = []
85
+ here_doc = false
86
+ here_word = ""
87
+ buf.each_line do |line|
88
+ if line =~ /(<<|<<~|<<-)[A-Z]+/
89
+ here_doc = true
90
+ here_word = line.match(/(<<|<<~|<<-)[A-Z]+/).to_s.gsub(/[<~-]/, "")
91
+ end
92
+ if here_word != "" and line =~ Regexp.new("^\s*#{here_word}$")
93
+ here_word = ""
94
+ here_doc = false
95
+ pp line
96
+ end
97
+ if here_doc == false
98
+ new_buf.push line
99
+ else
100
+ pp line
101
+ end
102
+ end
103
+ return new_buf.join("")
104
+ end
105
+
106
+ def create_uml_class(in_dir, out_file)
107
+ out = []
108
+ out.push "@startuml"
109
+
110
+ puts "in_dir = #{in_dir}"
111
+ main_composition_list = []
112
+ main_method_list = []
113
+ global_var = []
114
+
115
+ Dir.glob("#{in_dir}/**/*.{rb,ru}") do |f|
116
+ puts f
117
+ buf = ""
118
+ Tempfile.create("rufo") do |tmp_file|
119
+ FileUtils.cp(f, tmp_file.path)
120
+ kernel = Facter.value(:kernel)
121
+ if kernel == "windows"
122
+ open("|rubyw #{get_rufo_path} #{tmp_file.path}") do |f|
123
+ if f.read =~ /error/
124
+ puts "rufo error #{f}"
125
+ return
126
+ else
127
+ buf = File.binread tmp_file.path
128
+ end
129
+ end
130
+ else
131
+ open("|rufo #{tmp_file.path}") do |f|
132
+ if f.read =~ /error/
133
+ puts "rufo error #{f}"
134
+ return
135
+ else
136
+ buf = File.binread tmp_file.path
137
+ end
138
+ end
139
+ end
140
+ end
141
+
142
+ # コメント削除
143
+ buf.gsub!(/(([\/\"\'].*?[\/\"\'])|([^\/\"\'\)\s]*#.+?$))/) do |m|
144
+ if m[0] == "#" and m[0] != "{"
145
+ #puts "comment #{m}"
146
+ # コメント
147
+ ""
148
+ else
149
+ #puts "not comment #{m}"
150
+ # コメント以外
151
+ m
152
+ end
153
+ end
154
+ # ヒアドキュメント削除
155
+ buf = delete_here_doc(buf)
156
+
157
+ out_list = []
158
+ cstruct_list = []
159
+ block_count = 0
160
+ method_type = :public
161
+ class_name = ""
162
+ # ソースを解析
163
+ buf.each_line do |line|
164
+ next if line =~ /^[\r\n]*$/ # 空行は対象外
165
+
166
+ # ブロックの開始/終了
167
+ indent_num = line.match(/^[ ]+/).to_s.size / 2
168
+ if block_count == indent_num
169
+ # 変化なし
170
+ elsif block_count > indent_num
171
+ # ブロックの終了
172
+ block_count = indent_num
173
+ else
174
+ # ブロックの開始
175
+ block_count = indent_num
176
+ end
177
+
178
+ #line.gsub!(/\".+\"/, "\"delete_string\"") # 文字列を削除
179
+ if line =~ /^\s*class\s/
180
+ unless line =~ /<</ # 特異クラスではない
181
+ work = line.gsub(/class\s/, "")
182
+ class_name = work.split("<")[0].to_s.chomp.match(/[A-Z][A-Za-z0-9_:]+/).to_s
183
+ base_name = work.split("<")[1].to_s.chomp.match(/[A-Z][A-Za-z0-9_:]+/).to_s
184
+ class_name.gsub!(/::/, ".")
185
+ class_name.gsub!(/;/, "")
186
+ if out_list.size != 0 and out_list[-1].type == :class_start # classが連続している
187
+ class_name = out_list[-1].name + "." + class_name
188
+ out_list[-1].name = class_name
189
+ cstruct_list[-1].name = class_name
190
+ else
191
+ out_list.push CStruct.new(:class_start, class_name, block_count, [], [], [], [])
192
+ cstruct_list.push CStruct.new(:class_end, class_name, block_count, [], [], [], [])
193
+ end
194
+ #pp line if class_name == ""
195
+ if base_name != ""
196
+ #base_name.gsub!(/::/, ".")
197
+ cstruct_list[-1].inherit_list.push base_name
198
+ end
199
+ end
200
+ next unless line =~ /end\s*$/ # 1行で終了しない場合
201
+ elsif line =~ /^\s*module\s/
202
+ module_name = line.split(" ")[1].to_s.chomp
203
+ module_name.gsub!(/^[:]+/, "")
204
+ module_name.gsub!(/::/, ".")
205
+ module_name.gsub!(/;/, "")
206
+ out_list.push CStruct.new(:module_start, module_name, block_count, [], [], [], [])
207
+ cstruct_list.push CStruct.new(:module_end, module_name, block_count, [], [], [], [])
208
+ next unless line =~ /end\s*$/ # 1行で終了しない場合
209
+ end
210
+
211
+ if line =~ /^\s*private$/
212
+ method_type = :private
213
+ elsif line =~ /^\s*protected$/
214
+ method_type = :protected
215
+ elsif line =~ /^\s*public$/
216
+ method_type = :public
217
+ end
218
+
219
+ if line =~ /^\s*def\s/
220
+ # 関数名を取り出す
221
+ method = line.chomp.gsub(/\s*def\s*/, "")
222
+ unless method =~ /\(/
223
+ # 関数名にカッコをつける
224
+ sp = method.split(" ")
225
+ if sp.size > 1
226
+ method = sp[0].to_s + "(" + sp[1..-1].to_s + ")"
227
+ else
228
+ method = method + "()"
229
+ end
230
+ end
231
+ if cstruct_list.size != 0
232
+ method_list = cstruct_list[-1].method_list
233
+ case method_type
234
+ when :public
235
+ method_list.push "+ #{method}"
236
+ when :private
237
+ method_list.push "- #{method}"
238
+ when :protected
239
+ method_list.push "# #{method}"
240
+ end
241
+ else
242
+ main_method_list.push "+ #{method}"
243
+ end
244
+ end
245
+
246
+ # composition_list
247
+ line.match(/(([\/\"\')].*?\.new.*?[\/\"\'])|(?![\/\"\'])([a-zA-Z0-9_]+\.new))/) do |m|
248
+ if m.to_s[0] != "/" and m.to_s[0] != "\"" and m.to_s[0] != "'"
249
+ name = m.to_s.gsub(/\.new/, "").match(/[A-Z][A-Za-z0-9_]+/).to_s
250
+ if name != ""
251
+ if cstruct_list.size != 0
252
+ cstruct_list[-1].composition_list.push name
253
+ else
254
+ main_composition_list.push "main *-- #{name}"
255
+ end
256
+ end
257
+ end
258
+ end
259
+
260
+ # インスタンス変数
261
+ if line =~ /\s*@\S+/
262
+ if cstruct_list.size != 0
263
+ line.match(/@[a-zA-Z0-9_]+/) { |m|
264
+ instance_var = cstruct_list[-1].var_list
265
+ val = m.to_s.gsub(/@/, "")
266
+ case method_type
267
+ when :public
268
+ instance_var.push "+ #{val}"
269
+ when :private
270
+ instance_var.push "- #{val}"
271
+ when :protected
272
+ instance_var.push "# #{val}"
273
+ end
274
+ }
275
+ end
276
+ end
277
+
278
+ # 外部変数
279
+ line.match(/\$[a-zA-Z0-9_]+/) { |m|
280
+ global_var.push "+ #{m.to_s}"
281
+ }
282
+
283
+ # クラスの終了
284
+ if cstruct_list.size != 0
285
+ if block_count == cstruct_list[-1].block_count # block_countが一致
286
+ #puts "end of #{cstruct_list[-1].name}"
287
+ out_list.push cstruct_list[-1]
288
+ cstruct_list.slice!(-1) # 最後の要素を削除
289
+ end
290
+ end
291
+ #puts "#{block_count} #{line.chomp}"
292
+ end
293
+ if block_count != 0
294
+ # エラー
295
+ puts f
296
+ return ""
297
+ end
298
+
299
+ # UMLの出力
300
+ out = print_uml(out, out_list)
301
+ end
302
+
303
+ if main_method_list.size != 0 or
304
+ main_composition_list.size != 0 or
305
+ main_method_list.size != 0
306
+ out.push "class main {"
307
+ main_method_list.each do |mml|
308
+ out.push mml
309
+ end
310
+ # グローバル変数の出力
311
+ global_var.uniq.each do |gv|
312
+ out.push gv
313
+ end
314
+ out.push "}"
315
+ main_composition_list.uniq.each do |mcl|
316
+ out.push mcl
317
+ end
318
+ end
319
+
320
+ out.push "@enduml"
321
+ return out.join("\n")
322
+ end
@@ -1,3 +1,3 @@
1
- [
2
-
1
+ [
2
+
3
3
  ]