uml_architect 0.0.2 → 0.0.4

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.
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]