use_case_diagram 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +65 -0
- data/Rakefile +11 -0
- data/bin/use_case_diagram +30 -0
- data/lib/use_case_diagram/Actor.png +0 -0
- data/lib/use_case_diagram/actors.rb +75 -0
- data/lib/use_case_diagram/cu_relations.rb +15 -0
- data/lib/use_case_diagram/diagram.rb +129 -0
- data/lib/use_case_diagram/nodes.rb +63 -0
- data/lib/use_case_diagram/parser.rb +43 -0
- data/lib/use_case_diagram/support_nodes.rb +32 -0
- data/lib/use_case_diagram/use_case_diagram.treetop +181 -0
- data/lib/use_case_diagram/version.rb +3 -0
- data/lib/use_case_diagram.rb +10 -0
- data/test/lib/use_case_diagram/ej1.txt +17 -0
- data/test/lib/use_case_diagram/test_version.rb +64 -0
- data/test/test_helper.rb +3 -0
- data/use_case.gemspec +26 -0
- metadata +102 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 7cb0a1b24c6a4f7893337480579677fb697fdd48
|
4
|
+
data.tar.gz: 0e3d5f298934ee0b888b6b49678ffdd4d77b80eb
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 29219f1c48533930623dbe93733ee629b60577745cf523fbae4155057290181c2dc58220613a1773dda8ee2b3bc261cc752a46ccd4a23aa57eaae0b462283a29
|
7
|
+
data.tar.gz: 5304397c25394106241d7924d4fc1383eaf8376647e1d2d12bb7c80cb52dc8da8646f862cd73055cb8e624ed681c8bbe34b211b1cab8cf4e90d519bdd8c10ad5
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Dario Guerrero
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
# use_case_diagram
|
2
|
+
|
3
|
+
This gem can be used to generate use case diagrams in dot format by using a simpler syntaxis.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
gem install use_case_diagram
|
8
|
+
|
9
|
+
Or you may add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
gem 'use_case_diagram'
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install use_case_diagram
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
Create a text file with the use_case_diagram description (ej1.txt):
|
24
|
+
|
25
|
+
actor :user
|
26
|
+
actor :admin
|
27
|
+
|
28
|
+
node :login
|
29
|
+
node :logout
|
30
|
+
node :other
|
31
|
+
node :askpassword "Ask password"
|
32
|
+
|
33
|
+
:user uses :login, :other
|
34
|
+
|
35
|
+
:admin uses :logout
|
36
|
+
|
37
|
+
:login includes :askpassword, :askname
|
38
|
+
|
39
|
+
:logout extended :extend1_logout, :extend2_logout
|
40
|
+
:askname includes :askfirstname
|
41
|
+
:askname extended :asksecondname
|
42
|
+
|
43
|
+
Then you can parse it to create the dot file:
|
44
|
+
|
45
|
+
use_case_diagram ej1.txt > ej1.dot
|
46
|
+
|
47
|
+
and call dot to create a pdf or png:
|
48
|
+
|
49
|
+
dot -Tpdf -o ej1.pdf ej1.dot
|
50
|
+
|
51
|
+
Obviously, you need dot installed to make this conversion.
|
52
|
+
|
53
|
+
|
54
|
+
You can also use it with pipes:
|
55
|
+
|
56
|
+
use_case_diagram ej1.txt | dot -Tpdf -o ej1.pdf ej1.dot
|
57
|
+
|
58
|
+
|
59
|
+
## Contributing
|
60
|
+
|
61
|
+
1. Fork it
|
62
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
63
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
64
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
65
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'use_case_diagram'
|
4
|
+
|
5
|
+
def help
|
6
|
+
puts "Usage: $0 description_file"
|
7
|
+
end
|
8
|
+
|
9
|
+
|
10
|
+
input_file=ARGV.shift
|
11
|
+
|
12
|
+
if input_file.nil? || !File.exists?(input_file)
|
13
|
+
puts "Need input file"
|
14
|
+
help
|
15
|
+
exit
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
cont=File.read(input_file)
|
20
|
+
|
21
|
+
parse_result=Parser.parse(cont)
|
22
|
+
|
23
|
+
# puts parse_result.obj.inspect
|
24
|
+
|
25
|
+
|
26
|
+
if !parse_result.nil?
|
27
|
+
puts parse_result.obj.to_dot
|
28
|
+
else
|
29
|
+
raise "No dot file produced"
|
30
|
+
end
|
Binary file
|
@@ -0,0 +1,75 @@
|
|
1
|
+
actor_path=File.join(File.dirname(File.dirname(__FILE__)),'use_case_diagram','Actor.png')
|
2
|
+
|
3
|
+
|
4
|
+
ACTOR_TPL =<<END
|
5
|
+
|
6
|
+
#NAME# [shapefile="#{actor_path}", peripheries=0, style=solid, fixedsize=true, height=1.1, labeldistance=100, labelloc="b" #LABEL#];
|
7
|
+
|
8
|
+
END
|
9
|
+
|
10
|
+
class Actor
|
11
|
+
|
12
|
+
attr_accessor :name, :description
|
13
|
+
|
14
|
+
#-----------------------------------------
|
15
|
+
#
|
16
|
+
#-----------------------------------------
|
17
|
+
def initialize(name)
|
18
|
+
@name=name.to_s
|
19
|
+
@description=nil
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_dot
|
24
|
+
res=ACTOR_TPL
|
25
|
+
res=res.gsub('#NAME#',@name)
|
26
|
+
lab=''
|
27
|
+
if !@description.nil?
|
28
|
+
lab=' , label="'+@description.to_s+'"'
|
29
|
+
end
|
30
|
+
res=res.gsub('#LABEL#',lab)
|
31
|
+
return res
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
ACTORS_TPL = <<END
|
38
|
+
/* Actor Nodes */
|
39
|
+
|
40
|
+
#ACTOR#
|
41
|
+
|
42
|
+
END
|
43
|
+
|
44
|
+
|
45
|
+
class Actors
|
46
|
+
|
47
|
+
def initialize
|
48
|
+
@actors=[]
|
49
|
+
end
|
50
|
+
|
51
|
+
def count
|
52
|
+
@actors.count
|
53
|
+
end
|
54
|
+
|
55
|
+
def add(name)
|
56
|
+
a=name
|
57
|
+
if !a.is_a?(Actor)
|
58
|
+
a=Actor.new(name)
|
59
|
+
end
|
60
|
+
|
61
|
+
@actors<<a
|
62
|
+
end
|
63
|
+
|
64
|
+
def to_dot
|
65
|
+
res=ACTORS_TPL
|
66
|
+
@actors.each do |actor|
|
67
|
+
res=res.gsub('#ACTOR#',actor.to_dot+"\n#ACTOR#")
|
68
|
+
|
69
|
+
end
|
70
|
+
res=res.gsub('#ACTOR#',"")
|
71
|
+
|
72
|
+
return res
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
|
2
|
+
class Relation
|
3
|
+
|
4
|
+
attr_accessor :from_u, :to_u, :type
|
5
|
+
|
6
|
+
#-----------------------------------------
|
7
|
+
#
|
8
|
+
#-----------------------------------------
|
9
|
+
def initialize(type, from_u, to_u)
|
10
|
+
@from_u=from_u
|
11
|
+
@to_u=to_u
|
12
|
+
@type=type
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
|
2
|
+
DIAG_TPL = <<END
|
3
|
+
digraph G {
|
4
|
+
rankdir=LR;
|
5
|
+
labelloc="b";
|
6
|
+
peripheries=0;
|
7
|
+
|
8
|
+
#ACTORS#
|
9
|
+
|
10
|
+
#NODES#
|
11
|
+
|
12
|
+
edge [arrowhead=none];
|
13
|
+
|
14
|
+
#USES#
|
15
|
+
|
16
|
+
edge [arrowhead=none, arrowtail=open, label="<<extend>>", style=dashed, dir=both];
|
17
|
+
|
18
|
+
#EXTENDS#
|
19
|
+
|
20
|
+
edge [arrowhead=open, arrowtail=none, label="<<includes>>", style=dashed, dir=both];
|
21
|
+
|
22
|
+
#INCLUDES#
|
23
|
+
|
24
|
+
|
25
|
+
|
26
|
+
// #GENERALISES#
|
27
|
+
|
28
|
+
}
|
29
|
+
END
|
30
|
+
|
31
|
+
require 'actors.rb'
|
32
|
+
require 'nodes.rb'
|
33
|
+
require 'cu_relations'
|
34
|
+
|
35
|
+
class Diagram
|
36
|
+
|
37
|
+
attr_accessor :actors,:nodes
|
38
|
+
|
39
|
+
def initialize(file=nil)
|
40
|
+
@file=file
|
41
|
+
@actors=Actors.new
|
42
|
+
@nodes=Nodes.new
|
43
|
+
@uses={}
|
44
|
+
@extends={}
|
45
|
+
@includes={}
|
46
|
+
@generalises={}
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
def inspect
|
51
|
+
puts "Actors:#{@actors.count}"
|
52
|
+
puts "Nodes:#{@nodes.count}"
|
53
|
+
puts "Uses:#{@uses.count}"
|
54
|
+
puts "Includes:#{@includes.count}"
|
55
|
+
puts "Extends:#{@extends.count}"
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
def relate(relation,from_u,to_u)
|
60
|
+
if relation[from_u].nil?
|
61
|
+
relation[from_u]=[]
|
62
|
+
end
|
63
|
+
|
64
|
+
relation[from_u] << to_u
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
def uses(from_u,to_u)
|
69
|
+
relate(@uses,from_u,to_u)
|
70
|
+
end
|
71
|
+
|
72
|
+
def extends(from_u,to_u)
|
73
|
+
relate(@extends,from_u,to_u)
|
74
|
+
end
|
75
|
+
|
76
|
+
def includes(from_u,to_u)
|
77
|
+
relate(@includes,from_u,to_u)
|
78
|
+
end
|
79
|
+
|
80
|
+
def generalises(from_u,to_u)
|
81
|
+
relate(@generalises,from_u,to_u)
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
|
86
|
+
def relations_to_dot(relations)
|
87
|
+
res=''
|
88
|
+
relations.each do |from_use,to_use|
|
89
|
+
to_use.each do |to_u|
|
90
|
+
res += "#{from_use} -> #{to_u};\n"
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
return res
|
95
|
+
end
|
96
|
+
|
97
|
+
def uses_to_dot
|
98
|
+
return relations_to_dot(@uses)
|
99
|
+
end
|
100
|
+
|
101
|
+
def extends_to_dot
|
102
|
+
return relations_to_dot(@extends)
|
103
|
+
end
|
104
|
+
|
105
|
+
|
106
|
+
def includes_to_dot
|
107
|
+
return relations_to_dot(@includes)
|
108
|
+
end
|
109
|
+
|
110
|
+
def generalises_to_dot
|
111
|
+
return relations_to_dot(@generalises)
|
112
|
+
end
|
113
|
+
|
114
|
+
|
115
|
+
def to_dot
|
116
|
+
res=DIAG_TPL;
|
117
|
+
|
118
|
+
res=res.gsub('#ACTORS#',@actors.to_dot)
|
119
|
+
res=res.gsub('#NODES#',@nodes.to_dot)
|
120
|
+
res=res.gsub('#USES#',uses_to_dot)
|
121
|
+
|
122
|
+
res=res.gsub('#EXTENDS#',extends_to_dot)
|
123
|
+
res=res.gsub('#INCLUDES#',includes_to_dot)
|
124
|
+
res=res.gsub('#GENERALISES#',generalises_to_dot)
|
125
|
+
|
126
|
+
return res
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
class Node
|
2
|
+
|
3
|
+
attr_accessor :name,:description
|
4
|
+
|
5
|
+
|
6
|
+
#-----------------------------------------
|
7
|
+
#
|
8
|
+
#-----------------------------------------
|
9
|
+
def initialize(name)
|
10
|
+
@name=name.to_s
|
11
|
+
@description=nil
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
NODES_TPL = <<END
|
17
|
+
/* Use Case Nodes */
|
18
|
+
|
19
|
+
node [shape=ellipse, style=solid];
|
20
|
+
|
21
|
+
#NODE#
|
22
|
+
|
23
|
+
END
|
24
|
+
|
25
|
+
|
26
|
+
class Nodes
|
27
|
+
|
28
|
+
def initialize
|
29
|
+
@nodes=[]
|
30
|
+
end
|
31
|
+
|
32
|
+
def count
|
33
|
+
@nodes.count
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
def add(name)
|
38
|
+
|
39
|
+
n=name
|
40
|
+
if !n.is_a?(Node)
|
41
|
+
n=Node.new(name)
|
42
|
+
end
|
43
|
+
@nodes<<n
|
44
|
+
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
def to_dot
|
49
|
+
res=NODES_TPL
|
50
|
+
@nodes.each do |node|
|
51
|
+
desc=''
|
52
|
+
if !node.description.nil?
|
53
|
+
desc=' [label="'+node.description+'"]'
|
54
|
+
end
|
55
|
+
res=res.gsub('#NODE#',node.name+"#{desc};\n#NODE#")
|
56
|
+
end
|
57
|
+
|
58
|
+
res=res.gsub('#NODE#',"")
|
59
|
+
|
60
|
+
return res
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'treetop'
|
2
|
+
require 'use_case_diagram'
|
3
|
+
require 'support_nodes'
|
4
|
+
|
5
|
+
# Find out what our base path is
|
6
|
+
base_path = File.expand_path(File.dirname(__FILE__))
|
7
|
+
|
8
|
+
# Load our custom syntax node classes so the parser can use them
|
9
|
+
# require File.join(base_path, 'node_extensions.rb')
|
10
|
+
|
11
|
+
class Parser
|
12
|
+
|
13
|
+
base_path = File.expand_path(File.dirname(__FILE__))
|
14
|
+
|
15
|
+
Treetop.load(File.join(base_path, 'use_case_diagram'))
|
16
|
+
|
17
|
+
# puts "- Grammar loaded"
|
18
|
+
@@parser = UCaseParser.new
|
19
|
+
|
20
|
+
# puts "- Parser created loaded"
|
21
|
+
|
22
|
+
def self.parse(data)
|
23
|
+
|
24
|
+
# Pass the data to the parser instance
|
25
|
+
tree = @@parser.parse(data)
|
26
|
+
# puts "- Data parsed"
|
27
|
+
|
28
|
+
# If tree is nil then there was an error during parsing
|
29
|
+
# we need to report a simple error message to help the user
|
30
|
+
if(tree.nil?)
|
31
|
+
puts @@parser.failure_reason
|
32
|
+
puts @@parser.failure_line
|
33
|
+
puts @@parser.failure_column
|
34
|
+
|
35
|
+
puts "LINE WITH ERROR:#{data.split("\n")[@@parser.failure_line]}"
|
36
|
+
|
37
|
+
raise Exception, "Parse error at offset: #{@@parser.index}"
|
38
|
+
end
|
39
|
+
|
40
|
+
return tree
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class IntegerLiteral < Treetop::Runtime::SyntaxNode
|
2
|
+
end
|
3
|
+
|
4
|
+
class StringLiteral < Treetop::Runtime::SyntaxNode
|
5
|
+
end
|
6
|
+
|
7
|
+
class EmptyLine < Treetop::Runtime::SyntaxNode
|
8
|
+
def obj
|
9
|
+
nil
|
10
|
+
end
|
11
|
+
end
|
12
|
+
class CommentLine < Treetop::Runtime::SyntaxNode
|
13
|
+
|
14
|
+
def obj
|
15
|
+
nil
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class NewLine < Treetop::Runtime::SyntaxNode
|
20
|
+
def obj
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class Identifier < Treetop::Runtime::SyntaxNode
|
26
|
+
def obj
|
27
|
+
nil
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class Expression < Treetop::Runtime::SyntaxNode
|
32
|
+
end
|
@@ -0,0 +1,181 @@
|
|
1
|
+
grammar UCase
|
2
|
+
|
3
|
+
rule diagram
|
4
|
+
(actor / node / uses / incl / extd / commentline / whiteline / newline)*
|
5
|
+
{
|
6
|
+
def obj
|
7
|
+
d=Diagram.new
|
8
|
+
elements.map{|e| e.obj}.compact.flatten.each do |e|
|
9
|
+
if e.is_a?(Actor)
|
10
|
+
d.actors.add(e)
|
11
|
+
elsif e.is_a?(Node)
|
12
|
+
d.nodes.add(e)
|
13
|
+
elsif e.is_a?(Relation)
|
14
|
+
if e.type==:uses
|
15
|
+
d.uses(e.from_u,e.to_u)
|
16
|
+
elsif e.type==:includes
|
17
|
+
d.includes(e.from_u,e.to_u)
|
18
|
+
elsif e.type==:extended
|
19
|
+
d.extends(e.from_u,e.to_u)
|
20
|
+
end
|
21
|
+
else
|
22
|
+
raise "Unknown element in parse tree"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
return d
|
27
|
+
end
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
rule actor
|
32
|
+
space? 'actor' space ident:identifier desc:node_description? space? newline
|
33
|
+
{
|
34
|
+
def obj
|
35
|
+
n=Actor.new(ident.obj)
|
36
|
+
if !desc.nil? && desc.respond_to?(:obj)
|
37
|
+
n.description=desc.obj
|
38
|
+
end
|
39
|
+
return n
|
40
|
+
end
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
rule node
|
45
|
+
space? 'node' space ident:identifier desc:node_description? space? newline
|
46
|
+
{
|
47
|
+
def obj
|
48
|
+
n=Node.new(ident.obj)
|
49
|
+
if !desc.nil? && desc.respond_to?(:obj)
|
50
|
+
n.description=desc.obj
|
51
|
+
end
|
52
|
+
|
53
|
+
return n
|
54
|
+
end
|
55
|
+
}
|
56
|
+
end
|
57
|
+
|
58
|
+
rule node_description
|
59
|
+
space desc:quotedstring
|
60
|
+
{
|
61
|
+
def obj
|
62
|
+
eval(desc.text_value)
|
63
|
+
end
|
64
|
+
}
|
65
|
+
end
|
66
|
+
|
67
|
+
rule uses
|
68
|
+
space? id1:identifier space 'uses' space id2:identifier id3:id_list* space? newline
|
69
|
+
{
|
70
|
+
def obj
|
71
|
+
r=[]
|
72
|
+
r << Relation.new(:uses,id1.obj,id2.obj)
|
73
|
+
|
74
|
+
id3.elements.each do |rel|
|
75
|
+
r << Relation.new(:uses,id1.obj,rel.obj)
|
76
|
+
end
|
77
|
+
return r
|
78
|
+
end
|
79
|
+
}
|
80
|
+
end
|
81
|
+
|
82
|
+
rule incl
|
83
|
+
space? id1:identifier space 'includes' space id2:identifier id3:id_list* space? newline
|
84
|
+
{
|
85
|
+
def obj
|
86
|
+
r=[]
|
87
|
+
r << Relation.new(:includes,id1.obj,id2.obj)
|
88
|
+
|
89
|
+
id3.elements.each do |rel|
|
90
|
+
r << Relation.new(:includes,id1.obj,rel.obj)
|
91
|
+
end
|
92
|
+
return r
|
93
|
+
end
|
94
|
+
}
|
95
|
+
end
|
96
|
+
|
97
|
+
rule extd
|
98
|
+
space? id1:identifier space 'extended' space id2:identifier id3:id_list* space? newline
|
99
|
+
{
|
100
|
+
def obj
|
101
|
+
r=[]
|
102
|
+
r << Relation.new(:extended,id1.obj,id2.obj)
|
103
|
+
|
104
|
+
id3.elements.each do |rel|
|
105
|
+
r << Relation.new(:extended,id1.obj,rel.obj)
|
106
|
+
end
|
107
|
+
return r
|
108
|
+
end
|
109
|
+
}
|
110
|
+
end
|
111
|
+
|
112
|
+
|
113
|
+
rule id_list
|
114
|
+
space? ',' space? id1:(identifier)
|
115
|
+
{
|
116
|
+
def obj
|
117
|
+
id1.obj
|
118
|
+
end
|
119
|
+
}
|
120
|
+
end
|
121
|
+
|
122
|
+
|
123
|
+
# ':' ident:[a-zA-Z0-9_]+
|
124
|
+
rule identifier
|
125
|
+
':' ident:([^\s\n\,\;\:\-]+)
|
126
|
+
{
|
127
|
+
def obj
|
128
|
+
ident.text_value.to_sym
|
129
|
+
end
|
130
|
+
}
|
131
|
+
end
|
132
|
+
|
133
|
+
rule commentline
|
134
|
+
space? '#' (!"\n" .)+ newline
|
135
|
+
{
|
136
|
+
def obj
|
137
|
+
nil
|
138
|
+
end
|
139
|
+
|
140
|
+
}
|
141
|
+
end
|
142
|
+
|
143
|
+
|
144
|
+
rule quotedstring
|
145
|
+
'"' ('\"' / !'"' .)* '"'
|
146
|
+
{
|
147
|
+
def obj
|
148
|
+
nil
|
149
|
+
end
|
150
|
+
|
151
|
+
}
|
152
|
+
end
|
153
|
+
|
154
|
+
rule space
|
155
|
+
[ \t]+
|
156
|
+
end
|
157
|
+
|
158
|
+
rule whiteline
|
159
|
+
space newline
|
160
|
+
{
|
161
|
+
def obj
|
162
|
+
nil
|
163
|
+
end
|
164
|
+
}
|
165
|
+
end
|
166
|
+
|
167
|
+
rule newline
|
168
|
+
[\n]
|
169
|
+
{
|
170
|
+
def obj
|
171
|
+
nil
|
172
|
+
end
|
173
|
+
}
|
174
|
+
end
|
175
|
+
|
176
|
+
rule emptyline
|
177
|
+
''
|
178
|
+
end
|
179
|
+
|
180
|
+
|
181
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# $: << File.dirname(__FILE__)
|
2
|
+
$: << File.join(File.dirname(__FILE__),File.basename(__FILE__,File.extname(__FILE__)))
|
3
|
+
|
4
|
+
require "use_case_diagram/version"
|
5
|
+
require "use_case_diagram/diagram"
|
6
|
+
require "use_case_diagram/parser"
|
7
|
+
|
8
|
+
module UseCaseDiagram
|
9
|
+
# Your code goes here...
|
10
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
actor :user
|
2
|
+
actor :admin "Admin name"
|
3
|
+
|
4
|
+
node :login
|
5
|
+
node :logout
|
6
|
+
node :other
|
7
|
+
node :askpassword "Ask password"
|
8
|
+
|
9
|
+
:user uses :login, :other
|
10
|
+
|
11
|
+
:admin uses :logout
|
12
|
+
|
13
|
+
:login includes :askpassword, :askname
|
14
|
+
|
15
|
+
:logout extended :extend1_logout, :extend2_logout
|
16
|
+
:askname includes :askfirstname
|
17
|
+
:askname extended :asksecondname
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../test_helper.rb'
|
2
|
+
|
3
|
+
|
4
|
+
class TestUseCase < Test::Unit::TestCase
|
5
|
+
|
6
|
+
@@base_path=File.dirname(__FILE__)
|
7
|
+
|
8
|
+
def test_parse_empty
|
9
|
+
res=Parser.parse("")
|
10
|
+
|
11
|
+
assert(res.obj.is_a?(Diagram))
|
12
|
+
|
13
|
+
assert_equal(res.obj.actors.count,0)
|
14
|
+
assert_equal(res.obj.nodes.count,0)
|
15
|
+
# assert_equal(res.obj.uses.count,0)
|
16
|
+
# assert_equal(res.obj.includes.count,0)
|
17
|
+
# assert_equal(res.obj.extends.count,0)
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_parse_actor
|
22
|
+
res=Parser.parse("actor :dario\n")
|
23
|
+
|
24
|
+
assert(res.obj.is_a?(Diagram))
|
25
|
+
|
26
|
+
assert_equal(res.obj.actors.count,1)
|
27
|
+
assert_equal(res.obj.nodes.count,0)
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_parse_node
|
32
|
+
res=Parser.parse("node :login\n")
|
33
|
+
|
34
|
+
assert(res.obj.is_a?(Diagram))
|
35
|
+
|
36
|
+
assert_equal(res.obj.actors.count,0)
|
37
|
+
assert_equal(res.obj.nodes.count,1)
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_parse
|
42
|
+
res=Parser.parse("actor :dario\n node :login \n node :logout\n")
|
43
|
+
|
44
|
+
assert(res.obj.is_a?(Diagram))
|
45
|
+
|
46
|
+
assert_equal(res.obj.actors.count,1)
|
47
|
+
assert_equal(res.obj.nodes.count,2)
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_uses
|
52
|
+
cont=File.read(File.join(@@base_path,'ej1.txt'))
|
53
|
+
res=Parser.parse(cont)
|
54
|
+
|
55
|
+
assert(res.obj.is_a?(Diagram))
|
56
|
+
|
57
|
+
assert_equal(res.obj.actors.count,2)
|
58
|
+
assert_equal(res.obj.nodes.count,4)
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
|
64
|
+
end
|
data/test/test_helper.rb
ADDED
data/use_case.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'use_case_diagram/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "use_case_diagram"
|
8
|
+
spec.version = UseCaseDiagram::VERSION
|
9
|
+
spec.authors = ["Dario Guerrero"]
|
10
|
+
spec.email = ["dariogf@gmail.com"]
|
11
|
+
spec.description = %q{A gem to generate user cases in UML using dot}
|
12
|
+
spec.summary = %q{A gem to generate user cases in UML using dot}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib","lib/use_case_diagram"]
|
20
|
+
|
21
|
+
spec.add_runtime_dependency(%q<treetop>, ["= 1.4.12"])
|
22
|
+
|
23
|
+
|
24
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
25
|
+
spec.add_development_dependency "rake"
|
26
|
+
end
|
metadata
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: use_case_diagram
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Dario Guerrero
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2013-05-21 00:00:00 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: treetop
|
16
|
+
prerelease: false
|
17
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
18
|
+
requirements:
|
19
|
+
- - "="
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.4.12
|
22
|
+
type: :runtime
|
23
|
+
version_requirements: *id001
|
24
|
+
- !ruby/object:Gem::Dependency
|
25
|
+
name: bundler
|
26
|
+
prerelease: false
|
27
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
28
|
+
requirements:
|
29
|
+
- - ~>
|
30
|
+
- !ruby/object:Gem::Version
|
31
|
+
version: "1.3"
|
32
|
+
type: :development
|
33
|
+
version_requirements: *id002
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: rake
|
36
|
+
prerelease: false
|
37
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- &id004
|
40
|
+
- ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: "0"
|
43
|
+
type: :development
|
44
|
+
version_requirements: *id003
|
45
|
+
description: A gem to generate user cases in UML using dot
|
46
|
+
email:
|
47
|
+
- dariogf@gmail.com
|
48
|
+
executables:
|
49
|
+
- use_case_diagram
|
50
|
+
extensions: []
|
51
|
+
|
52
|
+
extra_rdoc_files: []
|
53
|
+
|
54
|
+
files:
|
55
|
+
- .gitignore
|
56
|
+
- Gemfile
|
57
|
+
- LICENSE.txt
|
58
|
+
- README.md
|
59
|
+
- Rakefile
|
60
|
+
- bin/use_case_diagram
|
61
|
+
- lib/use_case_diagram.rb
|
62
|
+
- lib/use_case_diagram/Actor.png
|
63
|
+
- lib/use_case_diagram/actors.rb
|
64
|
+
- lib/use_case_diagram/cu_relations.rb
|
65
|
+
- lib/use_case_diagram/diagram.rb
|
66
|
+
- lib/use_case_diagram/nodes.rb
|
67
|
+
- lib/use_case_diagram/parser.rb
|
68
|
+
- lib/use_case_diagram/support_nodes.rb
|
69
|
+
- lib/use_case_diagram/use_case_diagram.treetop
|
70
|
+
- lib/use_case_diagram/version.rb
|
71
|
+
- test/lib/use_case_diagram/ej1.txt
|
72
|
+
- test/lib/use_case_diagram/test_version.rb
|
73
|
+
- test/test_helper.rb
|
74
|
+
- use_case.gemspec
|
75
|
+
homepage: ""
|
76
|
+
licenses:
|
77
|
+
- MIT
|
78
|
+
metadata: {}
|
79
|
+
|
80
|
+
post_install_message:
|
81
|
+
rdoc_options: []
|
82
|
+
|
83
|
+
require_paths:
|
84
|
+
- lib
|
85
|
+
- lib/use_case_diagram
|
86
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- *id004
|
89
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
90
|
+
requirements:
|
91
|
+
- *id004
|
92
|
+
requirements: []
|
93
|
+
|
94
|
+
rubyforge_project:
|
95
|
+
rubygems_version: 2.0.3
|
96
|
+
signing_key:
|
97
|
+
specification_version: 4
|
98
|
+
summary: A gem to generate user cases in UML using dot
|
99
|
+
test_files:
|
100
|
+
- test/lib/use_case_diagram/ej1.txt
|
101
|
+
- test/lib/use_case_diagram/test_version.rb
|
102
|
+
- test/test_helper.rb
|