ruby-uml 0.2.2

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.
data/README ADDED
@@ -0,0 +1,61 @@
1
+ = Goal
2
+
3
+ <tt>ruby-uml</tt> tries to trace different aspects of an existing application,
4
+ which is intended to provide support for refactorisations by generating
5
+ UML-graphs.
6
+
7
+ <tt>ruby-uml</tt> is able to generate textual representations of the gathered
8
+ informations.
9
+
10
+ These representations include pic- or dot-code that can be converted to images
11
+ by their corresponding applications.
12
+
13
+ At this time <tt>ruby-uml</tt> is able to generate sequence- and class-diagrams.
14
+
15
+ As you won't get that much information out of the trace, the resulting dot- or
16
+ pic-files are intended to be as readable as possible, so that manual
17
+ corrections/additions are made as easy as possible.
18
+
19
+ = Dependencies
20
+ == Gem dependencies:
21
+
22
+ diff-lcs:: >= 1.1.2
23
+
24
+ == Other dependencies:
25
+
26
+ ruby:: ruby-uml is tested with 1.8.5
27
+
28
+ aspectr:: There are three aspectr projects known to me:
29
+
30
+ 0.3.5:: http://sourceforge.net/projects/aspectr/
31
+
32
+ 0.3.6:: http://rubyforge.org/projects/aspectr/
33
+
34
+ 0.4.0:: http://sourceforge.net/projects/aspectr-fork/
35
+
36
+ - None of them seem to be maintained anymore.
37
+ - Everyone provides the functionality needed for ruby-uml.
38
+ - Everyone seems to have issues on ruby 1.8.5.
39
+ In the additional folder i provide a patch for 0.4.0
40
+ which resolved all issues for me on linux and cygwin.
41
+
42
+ UMLGraph:: http://www.spinellis.gr/sw/umlgraph/
43
+
44
+ ruby-uml uses the sequence.pic file from the UMLGraph Project
45
+ for generating sequence-diagrams out of pic files.
46
+
47
+ ruby-uml is tested with 4.6.
48
+
49
+ GNU Plotutils:: http://www.gnu.org/software/plotutils/
50
+
51
+ Plotutils 'pic2plot' is used for generating
52
+ sequence-diagram-images out of pic files.
53
+
54
+ ruby-uml is tested with 2.4.1.
55
+
56
+ Graphviz:: http://graphviz.org/
57
+
58
+ Grapphviz 'dot' command is used to generate class-diagram-images
59
+ out of dot files.
60
+
61
+ ruby-uml is tested with 2.12.
@@ -0,0 +1,53 @@
1
+ diff -uNr aspectr-0-4-0-orig/install.rb aspectr-0-4-0/install.rb
2
+ --- aspectr-0-4-0-orig/install.rb 2007-02-10 15:36:50.229995653 +0100
3
+ +++ aspectr-0-4-0/install.rb 2007-02-10 16:02:55.456951649 +0100
4
+ @@ -8,7 +8,7 @@
5
+ $libdir = File.join(CONFIG["libdir"], "ruby", $version)
6
+
7
+ $bindir = CONFIG["bindir"]
8
+ -$sitedir = CONFIG["sitedir"]
9
+ +$sitedir = CONFIG["sitelibdir"]
10
+
11
+ installdir = "" # Use top-level! Is this good?
12
+
13
+ diff -uNr aspectr-0-4-0-orig/lib/aspectr.rb aspectr-0-4-0/lib/aspectr.rb
14
+ --- aspectr-0-4-0-orig/lib/aspectr.rb 2007-02-10 15:36:50.238995384 +0100
15
+ +++ aspectr-0-4-0/lib/aspectr.rb 2007-02-10 15:38:00.062553460 +0100
16
+ @@ -27,7 +27,7 @@
17
+ AROUND = :AROUND
18
+
19
+ def initialize(never_wrap = "^$ ")
20
+ - @never_wrap = /^__|^send$|^id$|^class$|#{never_wrap}/
21
+ + @never_wrap = /^__|^send$|^id$|^object_id$|^class$|#{never_wrap}/
22
+ end
23
+
24
+ def wrap(target, pre, post, *args, &condition)
25
+ @@ -146,7 +146,7 @@
26
+ aspect.send(advice, method, *args)
27
+ rescue Exception
28
+ a = $!
29
+ - raise AspectRException, "#{a.type} '#{a}' in advice #{advice}"
30
+ + raise AspectRException, "#{a.class} '#{a}' in advice #{advice}"
31
+ end
32
+ end
33
+ end
34
+ @@ -201,8 +201,8 @@
35
+ begin
36
+ exit_status = nil
37
+ #{__aop_advice_call_syntax(PRE, method, args)}
38
+ - exit_status = []
39
+ - return (exit_status.push(#{__aop_around_advice_call_syntax(method, mangled_method, args)}).last)
40
+ + exit_status = #{__aop_around_advice_call_syntax(method, mangled_method, args)}
41
+ + return exit_status
42
+ rescue Exception
43
+ puts \"got exception: \#{$!}\"
44
+ exit_status = true
45
+ @@ -246,7 +246,7 @@
46
+ end
47
+
48
+ def __aop_mangle(method)
49
+ - "__aop__#{self.object_id}_#{method.object_id}"['-'] = '_'
50
+ + "__aop__#{self.object_id}_#{method.object_id}".gsub(/-/, '_')
51
+ end
52
+
53
+ def __aop_alias(new, old, private = true)
@@ -0,0 +1,183 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+
5
+ require 'rubygems'
6
+ gem 'diff-lcs'
7
+ require 'diff/lcs'
8
+
9
+ # limitations:
10
+ # only one command per line
11
+
12
+ # finds used object_names in array
13
+ def find_used_object_names(array)
14
+ result = []
15
+ array.each do |line|
16
+ case line.strip
17
+ when /^(object|placeholder_object|pobject|actor|complete|active|inactive|delete|lifeline_constraint|lconstraint|lconstraint_below|begin_frame|end_frame|comment|connect_to_comment)[ ]*\(([^\), ]+)/
18
+ result << $2
19
+ when /^(message|return_message|rmessage|create_message|cmessage|destroy_message|dmessage)[ ]*\(([^, ]+),([^\), ]+)/
20
+ result << $2
21
+ result << $3
22
+ end
23
+ end
24
+ result.uniq
25
+ end
26
+
27
+ # find left- and rightmost object from used in objects
28
+ # objects is array with order
29
+ def find_frame_objects(used, objects)
30
+ indexes = used.collect { |u| objects.index(u) }
31
+ return objects[indexes.min], objects[indexes.max]
32
+ end
33
+
34
+ def find_lines(array, regexp)
35
+ result = []
36
+ array.each do |line|
37
+ case line.strip
38
+ when regexp
39
+ result << line
40
+ end
41
+ end
42
+ result
43
+ end
44
+
45
+ # finds lines with object_definitions
46
+ def find_object_definitions(array)
47
+ find_lines array, /^(object|placeholder_object|pobject|actor)[ ]*\(/
48
+ end
49
+
50
+ def find_copies(array)
51
+ find_lines array, /^copy/
52
+ end
53
+
54
+ def find_object_completions(array)
55
+ find_lines array, /^complete[ ]*\(/
56
+ end
57
+
58
+ def find_messages(array)
59
+ find_lines array, /^(message|return_message|rmessage|create_message|cmessage|destroy_message|dmessage|active|inactive|delete|lifeline_constraint|lconstraint|lconstraint_below|begin_frame|end_frame|comment|connect_to_comment)[ ]*\(/
60
+ end
61
+
62
+ def find_variables(array)
63
+ find_lines array, /=/
64
+ end
65
+
66
+ def read_file(name)
67
+ IO.readlines(name)
68
+ end
69
+
70
+ def write_file(name, content)
71
+ open(name, 'w') do |f|
72
+ f.write content
73
+ end
74
+ end
75
+
76
+ def make_frame(content, all, name, label)
77
+ result = []
78
+ unless content.empty?
79
+ bonds = find_frame_objects(find_used_object_names(content), all)
80
+ name = "#{name}_#{$frame_count += 1}"
81
+ result << "step();\n"
82
+ result << "begin_frame(#{bonds.first}, #{name}, \"#{label}\");\n"
83
+ result << "step();\n"
84
+ result += content
85
+ result << "step();\n"
86
+ result << "end_frame(#{bonds.last}, #{name});\n"
87
+ result << "step();\n"
88
+ end
89
+ result
90
+ end
91
+
92
+ def prepare_messages(left, right, all_objects)
93
+ result = []
94
+ eins = []
95
+ zwei = []
96
+ Diff::LCS.sdiff(left, right).each do |line|
97
+ case line.action
98
+ when '='
99
+ result << make_frame(eins, all_objects, 'Eins', $options[:left_title])
100
+ result << make_frame(zwei, all_objects, 'Zwei', $options[:right_title])
101
+ eins = []
102
+ zwei = []
103
+ result << line.old_element
104
+ when '!'
105
+ eins << line.old_element
106
+ zwei << line.new_element
107
+ when '+'
108
+ zwei << line.new_element
109
+ when '-'
110
+ eins << line.old_element
111
+ end
112
+ end
113
+ result << make_frame(eins, all_objects, 'Eins', $options[:left_title])
114
+ result << make_frame(zwei, all_objects, 'Zwei', $options[:right_title])
115
+ result
116
+ end
117
+
118
+
119
+
120
+
121
+
122
+ $options = {
123
+ :left_title => 'before',
124
+ :right_title => 'after'
125
+ }
126
+
127
+ OptionParser.new do |opts|
128
+ opts.banner = "Usage: #$0 [options] file1 file2"
129
+
130
+ opts.on('--left-title MANDATORY', 'Title of left file') do |string|
131
+ $options[:left_title] = string
132
+ end
133
+
134
+ opts.on('--right-title MANDATORY', 'Title of right file') do |string|
135
+ $options[:right_title] = string
136
+ end
137
+
138
+ opts.on_tail('-h', '--help', 'Show this message') do
139
+ puts opts
140
+ exit
141
+ end
142
+
143
+ end.parse!
144
+
145
+ if ARGV.length != 2
146
+ puts 'Too view Files given'
147
+ exit
148
+ end
149
+
150
+ $frame_count = 0
151
+
152
+ f1 = read_file(ARGV[0])
153
+ v1 = find_variables(f1)
154
+ c1 = find_copies(f1)
155
+ od1 = find_object_definitions(f1)
156
+ m1 = find_messages(f1)
157
+ oc1 = find_object_completions(f1)
158
+
159
+ f2 = read_file(ARGV[1])
160
+ v2 = find_variables(f2)
161
+ c2 = find_copies(f2)
162
+ od2 = find_object_definitions(f2)
163
+ m2 = find_messages(f2)
164
+ oc2 = find_object_completions(f2)
165
+
166
+ # so werden neue zeilen von File 2 an erste angehängt
167
+ c = (c1 + c2).uniq
168
+ v = (v1 + v2).uniq
169
+ od = (od1 + od2).uniq
170
+ o = find_used_object_names(od)
171
+ oc = (oc1 + oc2).uniq
172
+
173
+ result = []
174
+ result << ".PS\n"
175
+ result += c
176
+ result += v
177
+ result += od
178
+ result << "step();\n"
179
+ result += prepare_messages(m1, m2, o)
180
+ result << "step();\n"
181
+ result += oc
182
+ result << "\n.PE"
183
+ puts result
@@ -0,0 +1,69 @@
1
+ $:.push '../lib'
2
+
3
+ require 'uml/class_diagram'
4
+
5
+ module Automotive
6
+
7
+ class Car
8
+ def drive
9
+ 2
10
+ end
11
+
12
+ def steer
13
+ 'hard'
14
+ end
15
+
16
+ def honk
17
+ 'toot'
18
+ end
19
+ end
20
+
21
+ module FourWheelDrive
22
+ def drive
23
+ 4
24
+ end
25
+ end
26
+
27
+ module ServoSteering
28
+ def steer
29
+ 'easy'
30
+ end
31
+ end
32
+
33
+ class Rover < Car
34
+ include FourWheelDrive
35
+ include ServoSteering
36
+
37
+ def honk
38
+ 'roar'
39
+ end
40
+ end
41
+
42
+ class Mini < Car
43
+ end
44
+
45
+ class Garage < Array
46
+ def impress_neighbours
47
+ each do |car|
48
+ car.honk
49
+ end
50
+ end
51
+ end
52
+
53
+ end
54
+
55
+ cd = UML::ClassDiagram.new :show_private_methods => false,
56
+ :show_protected_methods => false,
57
+ :show_public_methods => true,
58
+ :cluster_packages => true,
59
+ :include => [/^Automotive/]
60
+
61
+ cd.include Automotive::Mini
62
+
63
+ garage = Automotive::Garage.new
64
+ garage << Automotive::Rover.new
65
+ garage.impress_neighbours
66
+
67
+ File.open('class_diagram_example.dot', 'w') { |file|
68
+ file.write cd.to_dot
69
+ }
@@ -0,0 +1,47 @@
1
+ $:.push '../lib'
2
+
3
+ require 'uml/highlevel_backtracer'
4
+ require 'temperature'
5
+
6
+ ts = TempSensor.new
7
+ ta = TempAlarm.new(ts)
8
+
9
+ class HighlevelTest
10
+
11
+ def initialize
12
+ @tracer = UML::HighlevelBacktracer.new
13
+ @tracer.add_observer self
14
+ end
15
+
16
+ def include(*args)
17
+ @tracer.include(*args)
18
+ end
19
+
20
+ def update(event, tracer)
21
+ right = tracer.call_stack[-1]
22
+ left = tracer.call_stack[-2]
23
+ case event
24
+ when :call
25
+ if left
26
+ print "#{left[:real_klass]}.#{left[:method_symbol]}"
27
+ end
28
+ print " -> "
29
+ print "#{right[:real_klass]}.#{right[:method_symbol]}"
30
+ puts "(#{right[:args].join(',')})"
31
+ when :return
32
+ if left
33
+ print "#{left[:real_klass]}.#{left[:method_symbol]}"
34
+ end
35
+ print " <- "
36
+ print "#{right[:real_klass]}.#{right[:method_symbol]}"
37
+ puts
38
+ end
39
+ end
40
+
41
+ end
42
+
43
+ tracer = HighlevelTest.new
44
+ tracer.include ts, :run, :changed, :notify_observers
45
+ tracer.include ta, :update
46
+
47
+ ts.run(25)
@@ -0,0 +1,13 @@
1
+ #!/bin/sh
2
+
3
+ # generate sequence-diagram with old version of a library
4
+ ruby -rtemperature_old sequence_diagram_generator.rb >sequence_diagram_example_old.pic
5
+ pic2plot -Tps sequence_diagram_example_old.pic >sequence_diagram_example_old.ps
6
+
7
+ # generate sequence-diagram with new version of a library
8
+ ruby -rtemperature_new sequence_diagram_generator.rb >sequence_diagram_example_new.pic
9
+ pic2plot -Tps sequence_diagram_example_new.pic >sequence_diagram_example_new.ps
10
+
11
+ # generate combined sequence_diagram out the two
12
+ ../bin/sequence_diagram_diff sequence_diagram_example_old.pic sequence_diagram_example_new.pic >sequence_diagram_example.pic
13
+ pic2plot -Tps sequence_diagram_example.pic >sequence_diagram_example.ps
@@ -0,0 +1,41 @@
1
+ $:.push '../lib'
2
+
3
+ require 'uml/sequence_diagram'
4
+
5
+ def callback(p)
6
+ case p
7
+ when Fixnum, TrueClass, FalseClass
8
+ p.to_s
9
+ when NilClass
10
+ 'nil'
11
+ when Array
12
+ '[' << p.collect(&method(:callback)).join(',') << ']'
13
+ else
14
+ p.class
15
+ end
16
+ end
17
+
18
+ sd = UML::SequenceDiagram.new(
19
+ :split_inherited => true,
20
+ :multiple_activation => true,
21
+ :use_create_message => true,
22
+ :object_sequence => ['Actor', 'TempSensor', 'Observable', 'Dummy', 'TempAlarm'],
23
+ :pic_variables => {
24
+ :boxwid => 0.85,
25
+ :movewid => 0.85,
26
+ :maxpswid => 50,
27
+ :maxpsht => 50,
28
+ },
29
+ :parameter_callback => method(:callback)
30
+ )
31
+
32
+ ts = TempSensor.new
33
+
34
+ sd.include ts, :run, :changed, :notify_observers, :add_observer
35
+ sd.include TempAlarm, :update, :initialize
36
+ sd.include IO, :puts
37
+
38
+ ta = TempAlarm.new ts
39
+ ts.run 27
40
+
41
+ puts sd.to_pic