umlify 0.3.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 ADDED
@@ -0,0 +1,19 @@
1
+ _ _ __
2
+ | (_)/ _|
3
+ _ _ _ __ ___ | |_| |_ _ _
4
+ | | | | '_ ` _ \| | | _| | | |
5
+ | |_| | | | | | | | | | | |_| |
6
+ \__,_|_| |_| |_|_|_|_| \__, |
7
+ __/ |
8
+ |___/
9
+
10
+ umlify is a tool that creates
11
+ uml class diagrams from your code
12
+
13
+ <https://github.com/mikaa123/umlify>
14
+
15
+
16
+ Introduction
17
+ ------------
18
+
19
+ umlify takes your project's source code and creates an uml class diagram out of it.
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require 'rake/testtask'
2
+ require 'bundler'
3
+ Bundler::GemHelper.install_tasks
4
+
5
+
6
+ Rake::TestTask.new do |t|
7
+ t.test_files = FileList['test/*_test.rb']
8
+ t.verbose = true
9
+ end
data/bin/umlify ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'umlify'
4
+
5
+ Umlify::Runner.new(ARGV).run
@@ -0,0 +1,44 @@
1
+ module Umlify
2
+
3
+ ##
4
+ # Creates and store a yUML api string for generating diagram
5
+ #
6
+ class Diagram
7
+
8
+ # Array containing yUML DSL statements
9
+ attr_accessor :statements
10
+
11
+ def initialize
12
+ @statements = []
13
+ end
14
+
15
+ def create &blk
16
+ instance_eval &blk
17
+ end
18
+
19
+ # Adds the given statement to the @diagram array
20
+ def add statement
21
+ # TODO: Add some sort of validation
22
+
23
+ @statements << statement if statement.is_a? String
24
+ if statement.is_a? UmlClass
25
+
26
+ if statement.associations.empty?
27
+ @statements << statement.to_s
28
+ else
29
+ @statements << statement.to_s
30
+
31
+ statement.associations.each do |name, type|
32
+ @statements << "[#{statement.name}]-#{name}>[#{type}]"
33
+ end
34
+ end
35
+
36
+ end
37
+ end
38
+
39
+ # Dumps the html of the diagram
40
+ def export
41
+ '<img src="http://yuml.me/diagram/class/'+@statements.join(", ")+'" />'
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,13 @@
1
+ # Extends the String to add a String#each method so that
2
+ # strings can be read just like files, line-by-line.
3
+
4
+ class String
5
+
6
+ def each
7
+
8
+ self.split(/\n/).each do |line|
9
+ yield line
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,79 @@
1
+ module Umlify
2
+
3
+ ##
4
+ # Parser is responsible for parsing ruby source files and building an array
5
+ # of uml classes
6
+ #
7
+ class Parser
8
+
9
+ # An array containing all the parsed classes
10
+ # type: UmlClass
11
+ attr_accessor :classes
12
+
13
+ # files should be an array containing file names with the correct path
14
+ def initialize files
15
+ @files = files
16
+ @classes = []
17
+ end
18
+
19
+ # Parses the source code of the files in @files
20
+ # to build uml classes. Returns an array containing all the
21
+ # parsed classes or nil if no ruby file were found in the
22
+ # @files array.
23
+ def parse_sources!
24
+
25
+ @source_files = @files.select {|f| f.match /\.rb/}
26
+ return nil if @source_files.empty?
27
+
28
+ @source_files.each do |file|
29
+ f = File.open file, 'r'
30
+ (parse_file f).each {|c| @classes << c}
31
+ f.close
32
+ end
33
+
34
+ @classes
35
+ end
36
+
37
+ # Parse the given file or string, and return the parsed classes
38
+ def parse_file file
39
+ classes_in_file = []
40
+ current_class = nil
41
+ type_annotation = nil
42
+
43
+ file.each do |line|
44
+
45
+ # This parses the classes
46
+ line.match(/^\s*class ([\w]*)\b/) do |m|
47
+ current_class = UmlClass.new m[1]
48
+ classes_in_file << current_class
49
+ end
50
+
51
+ if current_class
52
+
53
+ # This parses the @variables
54
+ line.match(/@([\w]*)\b/) do |m|
55
+ current_class.variables << m[1] unless current_class.variables.include? m[1]
56
+ end
57
+
58
+ # This parses the methods
59
+ line.match(/def ([\w]*)\b/) do |m|
60
+ current_class.methods << m[1] unless current_class.methods.include? m[1]
61
+ end
62
+
63
+ # This raises the type_annotation flag
64
+ line.match(/# type: ([\w]*)\b/) {|m| type_annotation = m[1]}
65
+
66
+ # This adds an association to the current class, using the type_annotation
67
+ # if type_annotation has been set
68
+ line.match(/attr_accessor :([\w]*)\b/) do |m|
69
+ current_class.associations[m[1]] = type_annotation
70
+ type_annotation = nil
71
+ end if type_annotation
72
+
73
+ end
74
+ end
75
+
76
+ classes_in_file
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,72 @@
1
+ require 'optparse'
2
+
3
+ module Umlify
4
+
5
+ ###
6
+ # This class is instanciated and run by the bin file
7
+ #
8
+ class Runner
9
+
10
+ # Contains the options from the command line
11
+ attr_reader :args
12
+
13
+ # type: Parser
14
+ attr_accessor :parser
15
+
16
+ # type: Diagram
17
+ attr_accessor :diagram
18
+
19
+ # Takes as input an array with the command line options
20
+ def initialize args
21
+ @args = args
22
+ end
23
+
24
+ # Runs the application
25
+ def run
26
+ @args.push "-h" if @args.empty?
27
+
28
+ if @args[0][0] == '-'
29
+
30
+ OptionParser.new do |opts|
31
+ opts.banner = "Usage: umlify [option]"
32
+ opts.on("-h", "--help", "Shows this") do
33
+ puts opts
34
+ end
35
+ end.parse! @args
36
+
37
+ else
38
+ puts "umlifying"
39
+ if files = get_files_from_dir(ARGV[0])
40
+ puts "about to parse..."
41
+ @parser = Parser.new files
42
+
43
+ if classes = p.parse_sources!
44
+ @diagram = Diagram.new
45
+
46
+ diagram.create do
47
+ classes.each {|c| add c}
48
+ end
49
+
50
+ File.open("uml.html", 'w') do |file|
51
+ file << diagram.export
52
+ end
53
+
54
+ puts "Saved in uml.html"
55
+ else
56
+ puts "No ruby files in the directory"
57
+ end
58
+
59
+ else
60
+ puts "empty directory"
61
+ end
62
+ end
63
+
64
+ end
65
+
66
+ private
67
+
68
+ def get_files_from_dir directory
69
+ Dir[directory] unless Dir[directory].empty?
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,23 @@
1
+ module Umlify
2
+
3
+ ##
4
+ # Represent a parsed uml class
5
+ #
6
+ class UmlClass
7
+ attr_accessor :name, :variables, :methods, :associations
8
+
9
+ def initialize name
10
+ @name = name
11
+ @variables = []
12
+ @methods = []
13
+ @associations = {}
14
+ end
15
+
16
+ def to_s
17
+ '['+@name+'|'+
18
+ @variables.collect{|var| var}.join(";")+'|'+
19
+ @methods.collect{|met| met}.join(";")+']'
20
+ end
21
+ end
22
+ end
23
+
@@ -0,0 +1,3 @@
1
+ module Umlify
2
+ VERSION = "0.3.0"
3
+ end
data/lib/umlify.rb ADDED
@@ -0,0 +1,6 @@
1
+ require 'umlify/version'
2
+ require 'umlify/runner'
3
+ require 'umlify/parser'
4
+ require 'umlify/extension'
5
+ require 'umlify/uml_class'
6
+ require 'umlify/diagram'
@@ -0,0 +1,68 @@
1
+ require 'shoulda'
2
+ require 'umlify'
3
+
4
+ class DiagramTest < Test::Unit::TestCase
5
+
6
+ context "Diagram" do
7
+
8
+ setup do
9
+ @diagram = Umlify::Diagram.new
10
+ end
11
+
12
+ should "respond to create" do
13
+ assert_respond_to @diagram, :create
14
+ end
15
+
16
+ should "add Strings statements to diagram" do
17
+ test_statement = '[foo]->[bar]'
18
+ @diagram.create do
19
+ add test_statement
20
+ end
21
+
22
+ assert_equal ['[foo]->[bar]'], @diagram.statements
23
+ end
24
+
25
+ should "add UmlClass without associations to diagrams" do
26
+ test_uml_class = Umlify::UmlClass.new 'Unicorn'
27
+ test_uml_class.variables << 'foo_variable'
28
+ test_uml_class.methods << 'bar_method'
29
+
30
+ @diagram.create do
31
+ add test_uml_class
32
+ end
33
+
34
+ assert @diagram.statements.include? '[Unicorn|foo_variable|bar_method]'
35
+ end
36
+
37
+ should "add UmlClass with associations to diagrams" do
38
+ test_uml_class = Umlify::UmlClass.new 'Unicorn'
39
+ test_uml_class.variables << 'foo_variable'
40
+ test_uml_class.methods << 'bar_method'
41
+ test_uml_class.associations['foo'] = 'Bar'
42
+ test_uml_class.associations['chunky'] = 'Bacon'
43
+
44
+ @diagram.create do
45
+ add test_uml_class
46
+ end
47
+
48
+ assert @diagram.statements.include? '[Unicorn|foo_variable|bar_method]'
49
+ assert @diagram.statements.include? '[Unicorn]-foo>[Bar]'
50
+ assert @diagram.statements.include? '[Unicorn]-chunky>[Bacon]'
51
+ end
52
+
53
+ should "export th yUML html" do
54
+ test_uml_class = Umlify::UmlClass.new 'Unicorn'
55
+ test_uml_class.variables << 'foo_variable'
56
+ test_uml_class.methods << 'bar_method'
57
+
58
+ @diagram.create do
59
+ add test_uml_class
60
+ end
61
+
62
+ assert_equal '<img src="http://yuml.me/diagram/class/[Unicorn|foo_variable|bar_method]" />',
63
+ @diagram.export
64
+ end
65
+
66
+ end
67
+ end
68
+
@@ -0,0 +1,67 @@
1
+ require 'shoulda'
2
+ require 'umlify'
3
+
4
+ class ParserTest < Test::Unit::TestCase
5
+
6
+ context "Parser" do
7
+
8
+ setup do
9
+ fixture = ["somefile.rb", "someotherfile.rb"]
10
+ @p = Umlify::Parser.new fixture
11
+ end
12
+
13
+ should "respond to parse_sources!" do
14
+ assert_respond_to @p, :parse_sources!
15
+ end
16
+
17
+ should "return nil if no source file in the given directory" do
18
+ parser = Umlify::Parser.new ["not_source", "still_not_source"]
19
+ assert_equal nil, parser.parse_sources!
20
+ end
21
+
22
+ should "parse class names" do
23
+ test = <<-END_FILE
24
+ class AClassName
25
+ end
26
+ END_FILE
27
+ assert_equal 'AClassName', @p.parse_file(test)[0].name
28
+ end
29
+
30
+ should "parse @variables in classes" do
31
+ test = <<-END_FILE
32
+ class Bar
33
+ def foo
34
+ @a_variable = "foo"
35
+ end
36
+ end
37
+ END_FILE
38
+ bar = @p.parse_file(test)[0]
39
+ assert_instance_of Umlify::UmlClass, bar
40
+ assert bar.variables.include? "a_variable"
41
+ end
42
+
43
+ should "parse attr_accessor when preceeded by a # type: Type annotation" do
44
+ test = <<-END_FILE
45
+ class Bar
46
+
47
+ # type: FooBar
48
+ attr_accessor :unicorn
49
+
50
+ def foo
51
+ end
52
+ end
53
+ END_FILE
54
+ bar = @p.parse_file(test)[0]
55
+ assert_instance_of Umlify::UmlClass, bar
56
+ assert_equal "FooBar", bar.associations['unicorn']
57
+ end
58
+
59
+ should "return an array of UmlClasses when the parsing is done" do
60
+ p = Umlify::Parser.new Dir[File.dirname(__FILE__)+'/fixtures/*']
61
+ parsed_classes = p.parse_sources!
62
+ puts "here : #{parsed_classes}"
63
+ assert_equal 3, parsed_classes.count
64
+ end
65
+
66
+ end
67
+ end
metadata ADDED
@@ -0,0 +1,68 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: umlify
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.3.0
6
+ platform: ruby
7
+ authors:
8
+ - Michael Sokol
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-03-02 00:00:00 -05:00
14
+ default_executable:
15
+ dependencies: []
16
+
17
+ description:
18
+ email: mikaa123@gmail.com
19
+ executables:
20
+ - umlify
21
+ extensions: []
22
+
23
+ extra_rdoc_files: []
24
+
25
+ files:
26
+ - Rakefile
27
+ - README
28
+ - bin/umlify
29
+ - lib/umlify.rb
30
+ - lib/umlify/version.rb
31
+ - lib/umlify/runner.rb
32
+ - lib/umlify/parser.rb
33
+ - lib/umlify/extension.rb
34
+ - lib/umlify/uml_class.rb
35
+ - lib/umlify/diagram.rb
36
+ - test/parser_test.rb
37
+ - test/diagram_test.rb
38
+ has_rdoc: true
39
+ homepage: https://github.com/mikaa123/umlify
40
+ licenses: []
41
+
42
+ post_install_message:
43
+ rdoc_options: []
44
+
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ none: false
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: "0"
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: "0"
59
+ requirements: []
60
+
61
+ rubyforge_project:
62
+ rubygems_version: 1.5.0
63
+ signing_key:
64
+ specification_version: 3
65
+ summary: umlify is a tool that creates class diagrams from your code.
66
+ test_files:
67
+ - test/parser_test.rb
68
+ - test/diagram_test.rb