umlify 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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