ruby_uml_class 0.3.0 → 0.5.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,322 +1,323 @@
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
+ 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
+ if f =~ Regexp.new(@config["exclude_path"])
117
+ puts "skip #{f}"
118
+ next
119
+ end
120
+ puts f
121
+ buf = ""
122
+ Tempfile.create("rufo") do |tmp_file|
123
+ FileUtils.cp(f, tmp_file.path)
124
+ kernel = Facter.value(:kernel)
125
+ if kernel == "windows"
126
+ open("|rubyw #{get_rufo_path} #{tmp_file.path}") do |f|
127
+ if f.read =~ /error/
128
+ puts "rufo error #{f}"
129
+ return
130
+ else
131
+ buf = File.binread tmp_file.path
132
+ end
133
+ end
134
+ else
135
+ open("|rufo #{tmp_file.path}") do |f|
136
+ if f.read =~ /error/
137
+ puts "rufo error #{f}"
138
+ return
139
+ else
140
+ buf = File.binread tmp_file.path
141
+ end
142
+ end
143
+ end
144
+ end
145
+
146
+ # コメント削除
147
+ buf.gsub!(/(([\/\"\'].*?[\/\"\'])|([^\/\"\'\)\s]*#.+?$))/) do |m|
148
+ if m[0] == "#" and m[0] != "{"
149
+ #puts "comment #{m}"
150
+ # コメント
151
+ ""
152
+ else
153
+ #puts "not comment #{m}"
154
+ # コメント以外
155
+ m
156
+ end
157
+ end
158
+ # ヒアドキュメント削除
159
+ buf = delete_here_doc(buf)
160
+
161
+ out_list = []
162
+ cstruct_list = []
163
+ block_count = 0
164
+ method_type = :public
165
+ class_name = ""
166
+ # ソースを解析
167
+ buf.each_line do |line|
168
+ next if line =~ /^[\r\n]*$/ # 空行は対象外
169
+
170
+ # ブロックの開始/終了
171
+ indent_num = line.match(/^[ ]+/).to_s.size / 2
172
+ if block_count == indent_num
173
+ # 変化なし
174
+ elsif block_count > indent_num
175
+ # ブロックの終了
176
+ block_count = indent_num
177
+ else
178
+ # ブロックの開始
179
+ block_count = indent_num
180
+ end
181
+
182
+ #line.gsub!(/\".+\"/, "\"delete_string\"") # 文字列を削除
183
+ if line =~ /^\s*class\s/
184
+ unless line =~ /<</ # 特異クラスではない
185
+ work = line.gsub(/class\s/, "")
186
+ class_name = work.split("<")[0].to_s.chomp.match(/[A-Z][A-Za-z0-9_:]+/).to_s
187
+ base_name = work.split("<")[1].to_s.chomp.match(/[A-Z][A-Za-z0-9_:]+/).to_s
188
+ class_name.gsub!(/::/, ".")
189
+ class_name.gsub!(/;/, "")
190
+ if out_list.size != 0 and out_list[-1].type == :class_start # classが連続している
191
+ class_name = out_list[-1].name + "." + class_name
192
+ out_list[-1].name = class_name
193
+ cstruct_list[-1].name = class_name
194
+ else
195
+ out_list.push CStruct.new(:class_start, class_name, block_count, [], [], [], [])
196
+ cstruct_list.push CStruct.new(:class_end, class_name, block_count, [], [], [], [])
197
+ end
198
+ #pp line if class_name == ""
199
+ if base_name != ""
200
+ #base_name.gsub!(/::/, ".")
201
+ cstruct_list[-1].inherit_list.push base_name
202
+ end
203
+ end
204
+ next unless line =~ /end\s*$/ # 1行で終了しない場合
205
+ elsif line =~ /^\s*module\s/
206
+ module_name = line.split(" ")[1].to_s.chomp
207
+ module_name.gsub!(/^[:]+/, "")
208
+ module_name.gsub!(/::/, ".")
209
+ module_name.gsub!(/;/, "")
210
+ out_list.push CStruct.new(:module_start, module_name, block_count, [], [], [], [])
211
+ cstruct_list.push CStruct.new(:module_end, module_name, block_count, [], [], [], [])
212
+ next unless line =~ /end\s*$/ # 1行で終了しない場合
213
+ end
214
+
215
+ if line =~ /^\s*private$/
216
+ method_type = :private
217
+ elsif line =~ /^\s*protected$/
218
+ method_type = :protected
219
+ elsif line =~ /^\s*public$/
220
+ method_type = :public
221
+ end
222
+
223
+ if line =~ /^\s*def\s/
224
+ # 関数名を取り出す
225
+ method = line.chomp.gsub(/\s*def\s*/, "")
226
+ unless method =~ /\(/
227
+ # 関数名にカッコをつける
228
+ sp = method.split(" ")
229
+ if sp.size > 1
230
+ method = sp[0].to_s + "(" + sp[1..-1].to_s + ")"
231
+ else
232
+ method = method + "()"
233
+ end
234
+ end
235
+ if cstruct_list.size != 0
236
+ method_list = cstruct_list[-1].method_list
237
+ case method_type
238
+ when :public
239
+ method_list.push "+ #{method}"
240
+ when :private
241
+ method_list.push "- #{method}"
242
+ when :protected
243
+ method_list.push "# #{method}"
244
+ end
245
+ else
246
+ main_method_list.push "+ #{method}"
247
+ end
248
+ end
249
+
250
+ # composition_list
251
+ line.match(/[A-Z]([a-zA-Z:]+)\.[a-z]/) do |m|
252
+ #pp m
253
+ c_name = m.to_s.split(".")[0]
254
+ if cstruct_list.size != 0
255
+ cstruct_list[-1].composition_list.push c_name
256
+ else
257
+ main_composition_list.push "main *-- #{c_name}"
258
+ end
259
+ end
260
+
261
+ # インスタンス変数
262
+ if line =~ /\s*@\S+/
263
+ if cstruct_list.size != 0
264
+ line.match(/@[a-zA-Z0-9_]+/) { |m|
265
+ instance_var = cstruct_list[-1].var_list
266
+ val = m.to_s.gsub(/@/, "")
267
+ case method_type
268
+ when :public
269
+ instance_var.push "+ #{val}"
270
+ when :private
271
+ instance_var.push "- #{val}"
272
+ when :protected
273
+ instance_var.push "# #{val}"
274
+ end
275
+ }
276
+ end
277
+ end
278
+
279
+ # 外部変数
280
+ line.match(/\$[a-zA-Z0-9_]+/) { |m|
281
+ global_var.push "+ #{m.to_s}"
282
+ }
283
+
284
+ # クラスの終了
285
+ if cstruct_list.size != 0
286
+ if block_count == cstruct_list[-1].block_count # block_countが一致
287
+ #puts "end of #{cstruct_list[-1].name}"
288
+ out_list.push cstruct_list[-1]
289
+ cstruct_list.slice!(-1) # 最後の要素を削除
290
+ end
291
+ end
292
+ #puts "#{block_count} #{line.chomp}"
293
+ end
294
+ if block_count != 0
295
+ # エラー
296
+ puts f
297
+ return ""
298
+ end
299
+
300
+ # UMLの出力
301
+ out = print_uml(out, out_list)
302
+ end
303
+
304
+ if main_method_list.size != 0 or
305
+ main_composition_list.size != 0 or
306
+ main_method_list.size != 0
307
+ out.push "class main {"
308
+ main_method_list.each do |mml|
309
+ out.push mml
310
+ end
311
+ # グローバル変数の出力
312
+ global_var.uniq.each do |gv|
313
+ out.push gv
314
+ end
315
+ out.push "}"
316
+ main_composition_list.uniq.each do |mcl|
317
+ out.push mcl
318
+ end
319
+ end
320
+
321
+ out.push "@enduml"
322
+ return out.join("\n")
323
+ end
@@ -1,3 +1,3 @@
1
- [
2
-
1
+ [
2
+
3
3
  ]