umlify 1.0.0 → 1.2.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.
- data/README.md +17 -0
- data/lib/umlify.rb +2 -0
- data/lib/umlify/diagram.rb +31 -3
- data/lib/umlify/extension.rb +3 -0
- data/lib/umlify/parser_sexp.rb +7 -3
- data/lib/umlify/runner.rb +17 -7
- data/lib/umlify/uml_class.rb +33 -2
- data/lib/umlify/version.rb +1 -1
- data/test/diagram_test.rb +19 -11
- data/test/runner_test.rb +19 -0
- data/test/string_test.rb +15 -0
- data/test/uml_class_test.rb +53 -0
- metadata +8 -2
data/README.md
CHANGED
@@ -29,6 +29,9 @@ How to use
|
|
29
29
|
2. type: `umlify lib/*/*`
|
30
30
|
3. Open uml.html
|
31
31
|
|
32
|
+
If you want umlify to try to guess the types of the associations, use
|
33
|
+
`umlify -s lib/*/*` at step 2.
|
34
|
+
|
32
35
|
Example
|
33
36
|
-------
|
34
37
|
|
@@ -39,6 +42,7 @@ Here is umlify umlified:
|
|
39
42
|
Features
|
40
43
|
--------
|
41
44
|
|
45
|
+
* Tries to guess the types of the instance variables (smart mode)
|
42
46
|
* __new__ Use RubyParser instead of regular expression as of v1.0.0
|
43
47
|
* __new__ supports inhertiance (v0.4.2)
|
44
48
|
* supports associations (see "How to add associations to a diagram)
|
@@ -76,6 +80,19 @@ classes. However, if you want an association to be shown on your diagram simply
|
|
76
80
|
end
|
77
81
|
end
|
78
82
|
|
83
|
+
Smart mode
|
84
|
+
----------
|
85
|
+
|
86
|
+
If you use umlify with the `-s` or `--smart` option, it'll try to guess
|
87
|
+
the types of the associations based on the name of the instance
|
88
|
+
variables.
|
89
|
+
|
90
|
+
If you class variable is @duck, then it will try to create an
|
91
|
+
association with the "Duck" class, if it exists.
|
92
|
+
|
93
|
+
If your variable is @ducks, it will try to create an association with a
|
94
|
+
cardinality of '*' with a class called "Duck", if such a class exists.
|
95
|
+
|
79
96
|
Contribute
|
80
97
|
----------
|
81
98
|
|
data/lib/umlify.rb
CHANGED
@@ -11,6 +11,8 @@
|
|
11
11
|
# umlify is tool that generates uml from your ruby source files. It
|
12
12
|
# works using yUML.me web api.
|
13
13
|
#
|
14
|
+
# Copyright 2011 Michael Sokol
|
15
|
+
#
|
14
16
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
15
17
|
# of this software and associated documentation files (the "Software"), to deal
|
16
18
|
# in the Software without restriction, including without limitation the rights
|
data/lib/umlify/diagram.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module Umlify
|
2
2
|
|
3
3
|
# Creates and store a yUML api string for generating diagram
|
4
|
-
# type of @statements: 1..* String
|
4
|
+
# * type of @statements: 1..* String
|
5
5
|
class Diagram
|
6
6
|
|
7
7
|
attr_accessor :statements
|
@@ -12,6 +12,7 @@ module Umlify
|
|
12
12
|
|
13
13
|
def create &blk
|
14
14
|
instance_eval &blk
|
15
|
+
self
|
15
16
|
end
|
16
17
|
|
17
18
|
# Adds the given statement to the @diagram array
|
@@ -24,8 +25,10 @@ module Umlify
|
|
24
25
|
|
25
26
|
@statements << statement.to_s
|
26
27
|
|
27
|
-
if statement.
|
28
|
-
|
28
|
+
if statement.children
|
29
|
+
statement.children.each do |child|
|
30
|
+
@statements << "[#{statement.name}]^[#{child.name}]"
|
31
|
+
end
|
29
32
|
end
|
30
33
|
|
31
34
|
unless statement.associations.empty?
|
@@ -42,6 +45,31 @@ module Umlify
|
|
42
45
|
end
|
43
46
|
end
|
44
47
|
|
48
|
+
# Sorts the statements array so that
|
49
|
+
# 1. Class definitions
|
50
|
+
# 2. Inheritance
|
51
|
+
# 3. Associations
|
52
|
+
# Otherwise, strange behavior can happen in the downloadd graph
|
53
|
+
def compute!
|
54
|
+
class_def = /\[[\w;?|!]*\]/
|
55
|
+
inheritance = /\[(.*?)\]\^\[(.*?)\]/
|
56
|
+
association = /\[.*\]-.*>\[.*\]/
|
57
|
+
|
58
|
+
@statements.sort! do |x, y|
|
59
|
+
|
60
|
+
if x =~ class_def and y =~ inheritance
|
61
|
+
-1
|
62
|
+
elsif x =~ class_def and y =~ association
|
63
|
+
-1
|
64
|
+
elsif x =~ inheritance and y =~ association
|
65
|
+
-1
|
66
|
+
else
|
67
|
+
1
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
45
73
|
# Returns the yuml.me uri
|
46
74
|
def get_uri
|
47
75
|
uri = '/diagram/class/'+@statements.join(", ")
|
data/lib/umlify/extension.rb
CHANGED
data/lib/umlify/parser_sexp.rb
CHANGED
@@ -4,7 +4,7 @@ module Umlify
|
|
4
4
|
|
5
5
|
# Parses files using S-Expressions given by the RubyParser gem
|
6
6
|
#
|
7
|
-
#
|
7
|
+
# * type of @classes: 0..* UmlClass
|
8
8
|
#
|
9
9
|
class ParserSexp
|
10
10
|
|
@@ -28,7 +28,8 @@ module Umlify
|
|
28
28
|
(parse_file File.read(file)).each {|c| @classes << c}
|
29
29
|
end
|
30
30
|
|
31
|
-
|
31
|
+
# Removes duplicates between variables and associations in the class
|
32
|
+
@classes.each {|c| c.chomp! @classes}
|
32
33
|
end
|
33
34
|
|
34
35
|
# Parse the given string, and return the parsed classes
|
@@ -60,8 +61,11 @@ module Umlify
|
|
60
61
|
|
61
62
|
# Searching for a s(:const, :Const) right after the class name, which
|
62
63
|
# means the class inherits from a parents class, :Const
|
63
|
-
if class_s_exp[2] and class_s_exp[2][
|
64
|
+
if class_s_exp[2] and class_s_exp[2][0] == :const
|
64
65
|
uml_class.parent = class_s_exp[2][1].to_s
|
66
|
+
elsif class_s_exp[2] and class_s_exp[2][0] == :colon2
|
67
|
+
# If the parent class belongs to a module
|
68
|
+
uml_class.parent = class_s_exp[2][2].to_s
|
65
69
|
end
|
66
70
|
|
67
71
|
# Looks-up for instance methods
|
data/lib/umlify/runner.rb
CHANGED
@@ -1,23 +1,23 @@
|
|
1
1
|
require 'net/http'
|
2
|
+
require 'optparse'
|
2
3
|
|
3
4
|
module Umlify
|
4
5
|
|
5
6
|
# Class to run to execute umlify. It parses the ruby sources provided
|
6
7
|
# and generates and save a uml diagram using yUML API.
|
7
|
-
#
|
8
|
-
# type of @diagram: Diagram
|
9
|
-
# type of @args: 0..* String
|
10
|
-
# type of @parser: ParserSexp
|
11
|
-
#
|
12
8
|
class Runner
|
13
9
|
|
10
|
+
attr_reader :smart_mode
|
11
|
+
|
14
12
|
# Takes as input an array with file names
|
15
13
|
def initialize args
|
16
14
|
@args = args
|
15
|
+
@smart_mode = false
|
17
16
|
end
|
18
17
|
|
19
18
|
# Runs the application
|
20
19
|
def run
|
20
|
+
parse_options
|
21
21
|
|
22
22
|
if @args.empty?
|
23
23
|
puts "Usage: umlify [source directory]"
|
@@ -29,16 +29,20 @@ module Umlify
|
|
29
29
|
if classes = @parser.parse_sources!
|
30
30
|
@diagram = Diagram.new
|
31
31
|
|
32
|
+
if @smart_mode
|
33
|
+
classes.each {|c| c.infer_types! classes}
|
34
|
+
end
|
35
|
+
|
32
36
|
@diagram.create do
|
33
37
|
classes.each {|c| add c}
|
34
|
-
end
|
38
|
+
end.compute!
|
35
39
|
|
36
40
|
puts "Downloading the image from yUML, it shouldn't be long."
|
37
41
|
|
38
42
|
image = download_image
|
39
43
|
save_to_file image
|
40
44
|
|
41
|
-
puts
|
45
|
+
puts 'http://yuml.me'+@diagram.get_uri
|
42
46
|
puts "Saved in uml.png"
|
43
47
|
else
|
44
48
|
puts "No ruby files in the directory"
|
@@ -47,6 +51,12 @@ module Umlify
|
|
47
51
|
|
48
52
|
end
|
49
53
|
|
54
|
+
def parse_options
|
55
|
+
OptionParser.new do |opts|
|
56
|
+
opts.on("-s", "--smart") { @smart_mode = true }
|
57
|
+
end.parse! @args
|
58
|
+
end
|
59
|
+
|
50
60
|
# Downloads the image of the uml diagram from yUML
|
51
61
|
def download_image
|
52
62
|
Net::HTTP.start("yuml.me", 80) do |http|
|
data/lib/umlify/uml_class.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
module Umlify
|
2
2
|
|
3
|
-
#
|
3
|
+
# Represents a parsed uml class
|
4
4
|
class UmlClass
|
5
|
-
attr_accessor :name, :variables, :methods, :associations, :parent
|
5
|
+
attr_accessor :name, :variables, :methods, :associations, :parent, :children
|
6
6
|
|
7
7
|
def initialize name
|
8
8
|
@name = name
|
@@ -11,6 +11,37 @@ module Umlify
|
|
11
11
|
@associations = {}
|
12
12
|
end
|
13
13
|
|
14
|
+
# Deletes variables from the @variables array if they appear
|
15
|
+
# in an association.
|
16
|
+
# Sets the @children variable
|
17
|
+
def chomp! classes
|
18
|
+
@variables = @variables - @associations.keys unless @associations.nil?
|
19
|
+
@children = classes.select do |c|
|
20
|
+
if c.parent == @name
|
21
|
+
c.parent = nil
|
22
|
+
true
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Tries to create an association with the attributes in @variables.
|
28
|
+
def infer_types! classes
|
29
|
+
class_names = classes.collect {|c| c.name}
|
30
|
+
@variables.each do |attribute|
|
31
|
+
|
32
|
+
if class_names.include? attribute.classify
|
33
|
+
# A type has match with the attribute's name
|
34
|
+
@associations[attribute] = attribute.classify
|
35
|
+
|
36
|
+
# If it's a plural, adds a cardinality
|
37
|
+
if attribute == attribute.pluralize
|
38
|
+
@associations[attribute+'-n'] = '*'
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
chomp! classes
|
43
|
+
end
|
44
|
+
|
14
45
|
def to_s
|
15
46
|
'['+@name+'|'+
|
16
47
|
@variables.collect{|var| var}.join(";")+'|'+
|
data/lib/umlify/version.rb
CHANGED
data/test/diagram_test.rb
CHANGED
@@ -62,19 +62,19 @@ class DiagramTest < Test::Unit::TestCase
|
|
62
62
|
assert @diagram.statements.include? '[Unicorn]-foo 1..*>[Bar]'
|
63
63
|
end
|
64
64
|
|
65
|
-
should "add UmlClass with parent to diagrams" do
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
65
|
+
# should "add UmlClass with parent to diagrams" do
|
66
|
+
# test_uml_class = Umlify::UmlClass.new 'Unicorn'
|
67
|
+
# test_uml_class.variables << 'foo_variable'
|
68
|
+
# test_uml_class.methods << 'bar_method'
|
69
|
+
# test_uml_class.parent = "Foo"
|
70
70
|
|
71
|
-
|
72
|
-
|
73
|
-
|
71
|
+
# @diagram.create do
|
72
|
+
# add test_uml_class
|
73
|
+
# end
|
74
74
|
|
75
|
-
|
76
|
-
|
77
|
-
end
|
75
|
+
# assert @diagram.statements.include? '[Unicorn|foo_variable|bar_method]'
|
76
|
+
# assert @diagram.statements.include? '[Foo]^[Unicorn]'
|
77
|
+
# end
|
78
78
|
|
79
79
|
should "get the yuml uri" do
|
80
80
|
test_uml_class = Umlify::UmlClass.new 'Unicorn'
|
@@ -89,6 +89,14 @@ class DiagramTest < Test::Unit::TestCase
|
|
89
89
|
@diagram.get_uri
|
90
90
|
end
|
91
91
|
|
92
|
+
should "sort the statements so that the class declarations are first, then
|
93
|
+
the inheritance, then the associations" do
|
94
|
+
|
95
|
+
@diagram.statements = ['[Foo]^[Unicorn]', '[Unicorn]-foo 1..*>[Bar]', '[Unicorn|foo_variable|bar_method]']
|
96
|
+
@diagram.compute!
|
97
|
+
assert_equal ['[Unicorn|foo_variable|bar_method]', '[Foo]^[Unicorn]', '[Unicorn]-foo 1..*>[Bar]'], @diagram.statements
|
98
|
+
end
|
99
|
+
|
92
100
|
end
|
93
101
|
end
|
94
102
|
|
data/test/runner_test.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'shoulda'
|
2
|
+
require 'umlify'
|
3
|
+
|
4
|
+
class RunnerTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
context "Runner" do
|
7
|
+
|
8
|
+
should "be in smart mode when passed -s or --smart as an option" do
|
9
|
+
r = Umlify::Runner.new(["-s"])
|
10
|
+
r.run
|
11
|
+
assert r.smart_mode
|
12
|
+
r = Umlify::Runner.new(["--smart"])
|
13
|
+
r.run
|
14
|
+
assert r.smart_mode
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
data/test/string_test.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'shoulda'
|
2
|
+
require 'umlify'
|
3
|
+
|
4
|
+
class StringTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
context "String" do
|
7
|
+
|
8
|
+
should "should respond to #classify" do
|
9
|
+
assert_equal "Duck", "ducks".classify
|
10
|
+
assert_equal "PepperoniPizza", "pepperoni_pizzas".classify
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'shoulda'
|
2
|
+
require 'umlify'
|
3
|
+
|
4
|
+
class UmlClassTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
context "UmlClass" do
|
7
|
+
|
8
|
+
setup do
|
9
|
+
@class = Umlify::UmlClass.new 'Farm'
|
10
|
+
@class.variables = ['ducks', 'some_cows', 'farm_house']
|
11
|
+
@class.associations['ducks'] = 'Duck'
|
12
|
+
end
|
13
|
+
|
14
|
+
should "delete variables from the @variables array if they exist in association" do
|
15
|
+
@class.chomp! []
|
16
|
+
assert_equal false, @class.variables.include?('ducks')
|
17
|
+
end
|
18
|
+
|
19
|
+
should "create a list of children, given all the types available" do
|
20
|
+
foo = Umlify::UmlClass.new "Foo"
|
21
|
+
foo.parent = "Umlify"
|
22
|
+
|
23
|
+
bar = Umlify::UmlClass.new "Bar"
|
24
|
+
bar.parent = "Umlify"
|
25
|
+
|
26
|
+
umlify = Umlify::UmlClass.new "Umlify"
|
27
|
+
|
28
|
+
classes = [foo, bar, umlify]
|
29
|
+
classes.each {|c| c.chomp!(classes)}
|
30
|
+
|
31
|
+
assert umlify.children.include? foo
|
32
|
+
assert umlify.children.include? bar
|
33
|
+
assert_equal nil, foo.parent
|
34
|
+
assert_equal nil, bar.parent
|
35
|
+
end
|
36
|
+
|
37
|
+
should "be able to infer types for associations with the variables in @variables" do
|
38
|
+
classes = [Umlify::UmlClass.new("Foo"), Umlify::UmlClass.new("Bar")]
|
39
|
+
foo_bar = Umlify::UmlClass.new "FooBar"
|
40
|
+
foo_bar.variables = ["foo", "bars", "args"]
|
41
|
+
classes << foo_bar
|
42
|
+
|
43
|
+
foo_bar.infer_types! classes
|
44
|
+
|
45
|
+
assert_equal 'Foo', foo_bar.associations['foo']
|
46
|
+
assert_equal 'Bar', foo_bar.associations['bars']
|
47
|
+
assert_equal '*', foo_bar.associations['bars-n']
|
48
|
+
assert_equal nil, foo_bar.associations['args']
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: umlify
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 1.
|
5
|
+
version: 1.2.0
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Michael Sokol
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-03-
|
13
|
+
date: 2011-03-10 00:00:00 -05:00
|
14
14
|
default_executable:
|
15
15
|
dependencies: []
|
16
16
|
|
@@ -36,6 +36,9 @@ files:
|
|
36
36
|
- lib/umlify/diagram.rb
|
37
37
|
- test/parser_test.rb
|
38
38
|
- test/diagram_test.rb
|
39
|
+
- test/uml_class_test.rb
|
40
|
+
- test/runner_test.rb
|
41
|
+
- test/string_test.rb
|
39
42
|
- test/parser_sexp_test.rb
|
40
43
|
has_rdoc: true
|
41
44
|
homepage: https://github.com/mikaa123/umlify
|
@@ -67,5 +70,8 @@ specification_version: 3
|
|
67
70
|
summary: umlify is a tool that creates class diagrams from your code.
|
68
71
|
test_files:
|
69
72
|
- test/parser_test.rb
|
73
|
+
- test/uml_class_test.rb
|
70
74
|
- test/parser_sexp_test.rb
|
71
75
|
- test/diagram_test.rb
|
76
|
+
- test/runner_test.rb
|
77
|
+
- test/string_test.rb
|