uml_architect 0.0.2 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/README.md +40 -2
  4. data/architect.gemspec +1 -0
  5. data/bin/architect +9 -8
  6. data/examples/class_with_details.yuml +1 -1
  7. data/examples/composition_and_aggregation.yuml +2 -0
  8. data/examples/dependancy.yuml +1 -0
  9. data/examples/inheritance.yuml +2 -0
  10. data/examples/notes.yuml +2 -1
  11. data/examples/{color_and_utf8.yuml → pending/color_and_utf8.yuml} +0 -0
  12. data/examples/{interface.yuml → pending/interface.yuml} +0 -0
  13. data/examples/{interface_inheritance.yuml → pending/interface_inheritance.yuml} +0 -0
  14. data/examples/{international_characters.yuml → pending/international_characters.yuml} +0 -0
  15. data/examples/{something_meaty.yuml → pending/something_meaty.yuml} +0 -0
  16. data/examples/simple_association.yuml +1 -1
  17. data/examples/{class.yuml → simple_class.yuml} +0 -0
  18. data/lib/architect.rb +1 -1
  19. data/lib/architect/association.rb +22 -8
  20. data/lib/architect/class.rb +2 -1
  21. data/lib/architect/diagram.rb +5 -4
  22. data/lib/architect/edge.rb +0 -1
  23. data/lib/architect/node.rb +0 -1
  24. data/lib/architect/note.rb +17 -0
  25. data/lib/architect/parser.rb +21 -9
  26. data/lib/architect/runner.rb +1 -0
  27. data/lib/architect/version.rb +1 -1
  28. data/spec/lib/association_spec.rb +9 -3
  29. data/spec/lib/diagram_spec.rb +8 -4
  30. data/spec/lib/note_spec.rb +12 -0
  31. data/spec/lib/parser_spec.rb +5 -0
  32. data/spec/lib/runner_spec.rb +2 -2
  33. metadata +27 -12
  34. data/examples/aggregation.yuml +0 -1
  35. data/examples/cardinality.yuml +0 -1
  36. data/examples/composition.yuml +0 -1
  37. data/examples/dependancies.yuml +0 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5e3e99db12409ac2ec2f6368b6840caff915de1d
4
- data.tar.gz: d36b07f16eaca893037cc8d9eaf8828b8cf22810
3
+ metadata.gz: fcf588256acefa798a448fa32320d55ee3f05a55
4
+ data.tar.gz: c1e2454709dac2ab62e0b19e314c4116769829fa
5
5
  SHA512:
6
- metadata.gz: 536c4249dacecd20bf502b79e91e916c7727eed00c346eed208d4f704d57b6e56dafcde93824f7d0bf172d94a25e675fd2e871ce428a99a60bbea3a3f1a4274a
7
- data.tar.gz: 51382b513dd71f722c7ed95baf6a58cc9138f9ffec02b18376a368bb736db5c60e8b693539c1553ed2cc462d33b346a77d6e081270811f493c93cb7d46ca61be
6
+ metadata.gz: 4f9ebbe1d97f49c96afd4fad7daeaecaaae01aa2c21525ab05a52b17c1d039d064195cbd60cc0fe256a3bb2bafa52b929e6423b87ccf21f0668a703da08ee3cc
7
+ data.tar.gz: 508072ac21f5e4223c247b2fdd07aaf58e4ffeb6e2d97748b90d843011fc024f66c7112f2408292474dd7faa92b5d9d38da1c169738cbca2335246a16e33a6c7
data/.gitignore CHANGED
@@ -16,3 +16,4 @@ spec/reports
16
16
  test/tmp
17
17
  test/version_tmp
18
18
  tmp
19
+ /*.svg
data/README.md CHANGED
@@ -9,9 +9,47 @@ Create UML Class diagrams using a [yUML](http://yuml.me/diagram/scruffy/class/sa
9
9
 
10
10
  ## Usage
11
11
 
12
- $ architect file
12
+ $ architect [file ...]
13
13
 
14
- For what should be in the input file check out yUML samples above.
14
+ This generates a output file with a svg extension with the same base name as the
15
+ input file.
16
+
17
+ ## Examples
18
+
19
+ ### Simple Class
20
+ [User]
21
+ ![Simple Class](http://whistler.github.io/architect/examples/simple_class.svg)
22
+
23
+ ### Class with methods and attributes
24
+ [User|+Firstname;+Lasname;-Password;|+Login();+Logout()]
25
+ ![Class with details](http://whistler.github.io/architect/examples/class_with_details.svg)
26
+
27
+ ### Simple Association
28
+ [User]-[Tweet]
29
+ ![Simple Association](http://whistler.github.io/architect/examples/simple_association.svg)
30
+
31
+ ### Inheritance
32
+ [Animal]^-[Cat]
33
+ [Animal]^-[Dog]
34
+ ![Inheritance](http://whistler.github.io/architect/examples/inheritance.svg)
35
+
36
+ ### Composition and Aggregation
37
+ [Car]++0..1-1[Carburetor]
38
+ [Pong]+0..1-0..*[Duck]
39
+ ![Composition and Aggregation](http://whistler.github.io/architect/examples/composition_and_aggregation.svg)
40
+
41
+ ### Directional Association
42
+ [Order]-billing >[Address], [Order]-shipping >[Address]
43
+ ![Directional Association](http://whistler.github.io/architect/examples/directional_association.svg)
44
+
45
+ ### Dependency
46
+ [REST]uses-.->[HTTP]
47
+ ![Dependency](http://whistler.github.io/architect/examples/dependancy.svg)
48
+
49
+ ### Notes
50
+ [note: this is a note]
51
+ [note: This is a note about user]-.-[User]
52
+ ![Notes](http://whistler.github.io/architect/examples/notes.svg)
15
53
 
16
54
  ## Contributing
17
55
 
@@ -19,6 +19,7 @@ Gem::Specification.new do |spec|
19
19
  spec.require_paths = ["lib"]
20
20
 
21
21
  spec.add_dependency "ruby-graphviz"
22
+ spec.add_dependency "libxslt-ruby"
22
23
  spec.add_dependency "listen", "2.0"
23
24
 
24
25
  spec.add_development_dependency "bundler", "~> 1.3"
@@ -2,13 +2,14 @@
2
2
  $: << "./lib"
3
3
  require 'architect/runner'
4
4
 
5
- if ARGV.count != 1
6
- puts "usage: architect file"
5
+ if ARGV.count == 0
6
+ puts "usage: architect [file ...]"
7
7
  else
8
- file = ARGV[0]
9
- if File.exists?(file)
10
- Architect::Runner.new(file, 'png')
11
- else
12
- puts file + " does not exist"
8
+ ARGV.each do |file|
9
+ if File.exists?(file)
10
+ Architect::Runner.new(file, 'svg')
11
+ else
12
+ puts file + ": file does not exist"
13
+ end
13
14
  end
14
- end
15
+ end
@@ -1 +1 @@
1
- [User|+Forename+;Surname;+HashedPassword;-Salt|+Login();+Logout()]
1
+ [User|+Firstname;+Lasname;-Password;|+Login();+Logout()]
@@ -0,0 +1,2 @@
1
+ [Car]++0..1-1[Carburetor]
2
+ [Pong]+0..1-0..*[Duck]
@@ -0,0 +1 @@
1
+ [Service]uses-.->[HTTP]
@@ -0,0 +1,2 @@
1
+ [Animal]^-[Cat]
2
+ [Animal]^-[Dog]
@@ -1 +1,2 @@
1
- [Customer]<>1->*[Order], [Customer]-[note: Aggregate Root{bg:cornsilk}]
1
+ [note: this is a note]
2
+ [note: This is a note about user]-.-[User]
@@ -1 +1 @@
1
- [Customer]->[Billing Address]
1
+ [User]-[Tweet]
@@ -1,5 +1,5 @@
1
1
  require "architect/version"
2
2
 
3
3
  module Architect
4
- # Your code goes here...
4
+
5
5
  end
@@ -3,16 +3,16 @@ require_relative 'edge'
3
3
 
4
4
  module Architect
5
5
 
6
+ ## Association between two classes
6
7
  class Association < Edge
7
8
 
8
- attr_accessor :attributes, :graph
9
-
10
9
  TYPES = {
11
10
  "<>" => "odiamond",
12
11
  "+" => "odiamond",
13
12
  "++" => "diamond",
14
13
  "" => "none",
15
- ">" => "vee"
14
+ ">" => "vee",
15
+ "^" => "empty"
16
16
  }
17
17
 
18
18
  def initialize(node1, node2, markup="->")
@@ -21,16 +21,20 @@ module Architect
21
21
  end
22
22
 
23
23
  def parse_markup(markup)
24
- matches = /(.*)-(.*)/.match(markup)
24
+ matches = /(.*)-\.-(.*)/.match(markup)
25
+ matches = /(.*)-(.*)/.match(markup) if matches == nil
25
26
  left = matches[1]
26
27
  right = matches[2]
28
+ style = get_linestyle(markup)
27
29
  {arrowhead: get_arrow(right), arrowtail: get_arrow(left),
28
- headlabel: strip_arrow(right), taillabel: strip_arrow(left),
29
- dir: "both"}
30
+ headlabel: " " + get_label(right) + " ",
31
+ taillabel: " " + get_label(left) + " ",
32
+ dir: "both", style: style}
30
33
  end
31
34
 
35
+ # Return the type of arrow contained in the markup
32
36
  def get_arrow(string)
33
- tokens = /([<>+]+)/.match(string)
37
+ tokens = /([<>+\^]+)/.match(string)
34
38
  if tokens == nil
35
39
  return "none"
36
40
  else
@@ -38,7 +42,8 @@ module Architect
38
42
  end
39
43
  end
40
44
 
41
- def strip_arrow(string)
45
+ # Remove the arrow to get label
46
+ def get_label(string)
42
47
  return "" if string == nil
43
48
  TYPES.keys.each do |arrow|
44
49
  string = string.gsub(arrow, "")
@@ -46,6 +51,15 @@ module Architect
46
51
  return string
47
52
  end
48
53
 
54
+ def get_linestyle(string)
55
+ if /-\.-/.match(string) == nil
56
+ return "solid"
57
+ else
58
+ return "dashed"
59
+ end
60
+ end
61
+
62
+ # Add associations to Graphviz
49
63
  def graph(g)
50
64
  g.add_edges(@node1.graphnode, @node2.graphnode, @attributes)
51
65
  end
@@ -2,8 +2,8 @@ require_relative 'node'
2
2
 
3
3
  module Architect
4
4
 
5
+ # Class in a class diagram
5
6
  class Class < Architect::Node
6
-
7
7
  attr_accessor :graphnode, :markup
8
8
 
9
9
  def initialize(markup)
@@ -21,6 +21,7 @@ module Architect
21
21
  return "{" + markup.gsub(";", "\\n") + "}"
22
22
  end
23
23
 
24
+ # Add class to Graphviz
24
25
  def graph(g)
25
26
  @graphnode = g.add_nodes(@markup, @style)
26
27
  end
@@ -2,21 +2,22 @@ require 'graphviz'
2
2
  require_relative 'parser'
3
3
 
4
4
  module Architect
5
- ##
5
+
6
6
  # Diagram is the base class for generating any diagram.
7
7
  class Diagram
8
+
8
9
  # Draw
9
10
  # [diagram] string containing the markup of the diagram
10
- def draw(diagram, output = "class_diagram.png", ext = 'png')
11
+ def draw(diagram, output = "class_diagram.svg", ext = 'svg')
11
12
  parser = Parser.new
12
13
  elements = parser.parse(diagram)
13
14
  graph = GraphViz.new("ClassDiagram", type: "digraph")
14
- graph.node["fillcolor"] = "gray95"
15
+ graph.node["fillcolor"] = "lightgrey"
15
16
  graph.node["style"] = "filled"
16
17
  elements.each do |element|
17
18
  element.graph(graph)
18
19
  end
19
- graph.output(ext.to_sym => output)
20
+ graph.output(ext.to_sym => output, nothugly: true)
20
21
  end
21
22
 
22
23
  end
@@ -2,7 +2,6 @@ require_relative 'node'
2
2
 
3
3
  module Architect
4
4
 
5
- ###
6
5
  # This is a generic edge in a graph which connects two nodes
7
6
  class Edge
8
7
  attr_accessor :from, :to
@@ -1,6 +1,5 @@
1
1
  module Architect
2
2
 
3
- ##
4
3
  # Generic class to create a graph node
5
4
  class Node
6
5
 
@@ -0,0 +1,17 @@
1
+ module Architect
2
+
3
+ # A note in a class diagram
4
+ class Note < Architect::Node
5
+ attr_accessor :graphnode
6
+
7
+ def initialize(markup)
8
+ matches = /note:(.+)/i.match(markup)
9
+ @markup = matches[1].strip
10
+ @style = {shape: "note", style: "filled", fillcolor: "lightgrey"}
11
+ end
12
+
13
+ def graph(g)
14
+ @graphnode = g.add_nodes(@markup, @style)
15
+ end
16
+ end
17
+ end
@@ -1,8 +1,9 @@
1
1
  require_relative 'class'
2
+ require_relative 'note'
2
3
  require_relative 'association'
3
4
 
4
5
  module Architect
5
- ##
6
+
6
7
  # Parses yUML files
7
8
  class Parser
8
9
 
@@ -36,18 +37,29 @@ module Architect
36
37
  # [statement] String containing statement
37
38
  # Returns a list of classes markup and association markup in the statement
38
39
  def parse_statement(statement)
39
- pattern = /\[(?<class1>.+?)\](?<association>.+?)\[(?<class2>.+)\]/
40
+ pattern = /\[(?<node1>.+?)\](?<association>.+?)\[(?<node2>.+)\]/
40
41
  tokens = pattern.match(statement)
41
42
  if tokens
42
- class1 = Class.new(tokens[:class1])
43
- class2 = Class.new(tokens[:class2])
44
- association = Association.new(class1, class2, tokens[:association])
45
- return [class1, class2, association]
43
+ node1 = get_node(tokens[:node1])
44
+ node2 = get_node(tokens[:node2])
45
+ association = Association.new(node1, node2, tokens[:association])
46
+ return [node1, node2, association]
46
47
  else
47
- tokens = /\[(?<class1>.*)\]/.match(statement)
48
- class1 = Class.new(tokens[:class1])
49
- return [class1]
48
+ tokens = /\[(?<node1>.*)\]/.match(statement)
49
+ node1 = get_node(tokens[:node1])
50
+ return [node1]
50
51
  end
51
52
  end
53
+
54
+ # [markup] string containing content inside square brackets
55
+ # Returns Note or Class
56
+ def get_node(markup)
57
+ if /^note/i.match(markup) != nil
58
+ return Note.new(markup)
59
+ else
60
+ return Class.new(markup)
61
+ end
62
+ end
63
+
52
64
  end
53
65
  end
@@ -2,6 +2,7 @@ require 'architect/diagram'
2
2
 
3
3
  module Architect
4
4
 
5
+ # Draws a diagram from a file
5
6
  class Runner
6
7
 
7
8
  def initialize(file, ext)
@@ -1,3 +1,3 @@
1
1
  module Architect
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.4"
3
3
  end
@@ -10,12 +10,13 @@ describe Architect::Association do
10
10
  end
11
11
 
12
12
  it "parses simple association" do
13
- @association.attributes[:arrowhead].should == "none"
13
+ attributes = @association.instance_eval("@attributes")
14
+ attributes[:arrowhead].should == "none"
14
15
  end
15
16
 
16
17
  it "parses association markup" do
17
18
  dot = {arrowhead: "vee", arrowtail: "odiamond",
18
- headlabel: "n", taillabel: "1", dir: "both"}
19
+ headlabel: " n ", taillabel: " 1 ", dir: "both", style: "solid"}
19
20
  @association.parse_markup("<>1-n>").should == dot
20
21
  end
21
22
 
@@ -24,7 +25,12 @@ describe Architect::Association do
24
25
  end
25
26
 
26
27
  it "strips arrows from strings" do
27
- @association.strip_arrow(">1").should == "1"
28
+ @association.get_label(">1").should == "1"
29
+ end
30
+
31
+ it "can draw dashed and solid lines" do
32
+ @association.get_linestyle("-").should == "solid"
33
+ @association.get_linestyle("-.-").should == "dashed"
28
34
  end
29
35
 
30
36
  end
@@ -8,19 +8,23 @@ describe Architect::Diagram do
8
8
  end
9
9
 
10
10
  it "can draw a class" do
11
- @diagram.send("draw", "[User]", "class.png")
11
+ @diagram.send("draw", "[User]", "class.svg")
12
12
  end
13
13
 
14
14
  it "can draw an association" do
15
- @diagram.send("draw", "[User]-[Pet]", "association.png")
15
+ @diagram.send("draw", "[User]-[Pet]", "association.svg")
16
16
  end
17
17
 
18
18
  it "can draw a class with attributes and methods" do
19
- @diagram.send("draw", "[User|name; age; height|login(); logout()]-[Pet]", "record.png")
19
+ @diagram.send("draw", "[User|name; age; height|login(); logout()]-[Pet]", "record.svg")
20
20
  end
21
21
 
22
22
  it "can draw a diagram with composition" do
23
- @diagram.send("draw", "[Pond]<>0..1-0..*[Duck]", "composition.png")
23
+ @diagram.send("draw", "[Pond]<>0..1-0..*[Duck]", "composition.svg")
24
+ end
25
+
26
+ it "can draw a note" do
27
+ @diagram.send("draw", "[note: This is a note about user]-.-[User]\n[note: this is a note]", "note.svg")
24
28
  end
25
29
 
26
30
  end
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+ require 'note'
3
+
4
+ describe Architect::Note do
5
+ it "can create note from markup" do
6
+ note = Architect::Note.new("note: hello world")
7
+ g = double()
8
+ g.should_receive(:add_nodes).with("hello world", {style: "filled",
9
+ shape: "note", fillcolor: "lightgrey"})
10
+ note.graph(g)
11
+ end
12
+ end
@@ -28,4 +28,9 @@ describe Architect::Parser do
28
28
  elements[0].name == "User"
29
29
  end
30
30
 
31
+ it "can parse a note" do
32
+ note = @parser.parse_statement("[Note: Hello]").first
33
+ note.class == Architect::Note
34
+ end
35
+
31
36
  end
@@ -7,12 +7,12 @@ describe Architect::Runner do
7
7
  it "should draw from file" do
8
8
  Architect::Diagram.any_instance.should_receive(:draw)
9
9
  Kernel.stub_chain(:open, :read).and_return("[User]")
10
- architect = Architect::Runner.new("tmp/example.yuml", 'png', false)
10
+ architect = Architect::Runner.new("tmp/example.yuml", 'png')
11
11
  end
12
12
 
13
13
  it "should be able to change extension" do
14
14
  Kernel.stub_chain(:open, :read).and_return("[User]")
15
- architect = Architect::Runner.new("test.yuml", "png", false)
15
+ architect = Architect::Runner.new("test.yuml", "png")
16
16
  architect.send(:change_extension, "test.yuml", "png").should == "test.png"
17
17
  end
18
18
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: uml_architect
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ibrahim Muhammad
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-10-10 00:00:00.000000000 Z
11
+ date: 2013-10-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ruby-graphviz
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - '>='
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: libxslt-ruby
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: listen
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -125,27 +139,26 @@ files:
125
139
  - Rakefile
126
140
  - architect.gemspec
127
141
  - bin/architect
128
- - examples/aggregation.yuml
129
- - examples/cardinality.yuml
130
- - examples/class.yuml
131
142
  - examples/class_with_details.yuml
132
- - examples/color_and_utf8.yuml
133
- - examples/composition.yuml
134
- - examples/dependancies.yuml
143
+ - examples/composition_and_aggregation.yuml
144
+ - examples/dependancy.yuml
135
145
  - examples/directional_association.yuml
136
146
  - examples/inheritance.yuml
137
- - examples/interface.yuml
138
- - examples/interface_inheritance.yuml
139
- - examples/international_characters.yuml
140
147
  - examples/notes.yuml
148
+ - examples/pending/color_and_utf8.yuml
149
+ - examples/pending/interface.yuml
150
+ - examples/pending/interface_inheritance.yuml
151
+ - examples/pending/international_characters.yuml
152
+ - examples/pending/something_meaty.yuml
141
153
  - examples/simple_association.yuml
142
- - examples/something_meaty.yuml
154
+ - examples/simple_class.yuml
143
155
  - lib/architect.rb
144
156
  - lib/architect/association.rb
145
157
  - lib/architect/class.rb
146
158
  - lib/architect/diagram.rb
147
159
  - lib/architect/edge.rb
148
160
  - lib/architect/node.rb
161
+ - lib/architect/note.rb
149
162
  - lib/architect/parser.rb
150
163
  - lib/architect/runner.rb
151
164
  - lib/architect/version.rb
@@ -154,6 +167,7 @@ files:
154
167
  - spec/lib/diagram_spec.rb
155
168
  - spec/lib/edge_spec.rb
156
169
  - spec/lib/node_spec.rb
170
+ - spec/lib/note_spec.rb
157
171
  - spec/lib/parser_spec.rb
158
172
  - spec/lib/runner_spec.rb
159
173
  - spec/spec_helper.rb
@@ -187,6 +201,7 @@ test_files:
187
201
  - spec/lib/diagram_spec.rb
188
202
  - spec/lib/edge_spec.rb
189
203
  - spec/lib/node_spec.rb
204
+ - spec/lib/note_spec.rb
190
205
  - spec/lib/parser_spec.rb
191
206
  - spec/lib/runner_spec.rb
192
207
  - spec/spec_helper.rb
@@ -1 +0,0 @@
1
- [Company]<>-1>[Location], [Location]+->[Point]
@@ -1 +0,0 @@
1
- [Customer]1-0..*[Address]
@@ -1 +0,0 @@
1
- [Company]++-1>[Location]
@@ -1 +0,0 @@
1
- [HttpContext]uses -.->[Response]