cadove 0.1

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.
@@ -0,0 +1,3 @@
1
+ 0.0.0
2
+ =====
3
+ Original release.
data/README ADDED
@@ -0,0 +1,34 @@
1
+ caDOVe (Domain Object Verifier)
2
+ ===============================
3
+
4
+ About
5
+ -----
6
+ caDOVe helps with checking if a Java code base and a UML model
7
+ of the domain objects are in sync. This is especially useful for
8
+ verifying the silver level compatibility requirement,
9
+ "bla bla bla bla bla".
10
+
11
+ Currently...
12
+ - only Hibernate annotated Java classes.
13
+ - only XMI representations of UML are supported.
14
+
15
+ Installation
16
+ ------------
17
+ 1. Install the RJB rubygem (http://rjb.rubyforge.org/)
18
+ 2. Set JAVA_HOME in your environment
19
+
20
+ Usage Example
21
+ -------------
22
+ require 'cadove'
23
+
24
+ CaDOVe.configure do
25
+ left 'nbia.xmi'
26
+ right 'nbia/domain'
27
+
28
+ ignore_classes %w(Boolean Date Double Integer Long String)
29
+
30
+ matching_classes(
31
+ :Image => :CTImage
32
+ )
33
+ end.class_comparison.attribute_comparison
34
+
@@ -0,0 +1,92 @@
1
+ require File.dirname(__FILE__) + '/cadove/models'
2
+
3
+ module CaDOVe
4
+ class << self
5
+ attr_writer :left, :right, :ignore_classes, :matching_classes
6
+
7
+ def configure(&block)
8
+ Configurator.module_eval &block
9
+ self
10
+ end
11
+
12
+ ###### CONFIGURATION PROPERTY ACCESSORS
13
+ %w(left right).each do |attribute|
14
+ required_accessor = <<-EOS
15
+ def #{attribute}
16
+ raise ConfigurationError.new("Bcsec::#{attribute} not set") unless @#{attribute}
17
+ @#{attribute}
18
+ end
19
+ EOS
20
+ class_eval(required_accessor)
21
+ end
22
+
23
+ def ignore_classes
24
+ @ignore_classes ||= []
25
+ end
26
+
27
+ def matching_classes
28
+ @matching_clases ||= {}
29
+ end
30
+
31
+ def class_comparison
32
+ Reports::ClassReport.new(comparison, left_type, right_type).display
33
+ self
34
+ end
35
+
36
+ def attribute_comparison
37
+ Reports::AttributeReport.new(comparison, left_type, right_type).display
38
+ self
39
+ end
40
+
41
+ protected
42
+ def left_representation
43
+ @left_representation ||= xmi?(left) ? XMI::XMIDocument.new(left) : Java::JavaSourceTree.new(left)
44
+ end
45
+
46
+ def right_representation
47
+ @right_representation ||= xmi?(right) ? XMI::XMIDocument.new(right) : Java::JavaSourceTree.new(right)
48
+ end
49
+
50
+ def comparison
51
+ @comparison ||= Analytics::Comparison.new(
52
+ left_representation.hashify,
53
+ right_representation.hashify,
54
+ :ignore_classes => @ignore_classes,
55
+ :matching_classes => @matching_classes
56
+ )
57
+ end
58
+
59
+ def xmi?(path)
60
+ path =~ /.*\.xmi$/i
61
+ end
62
+
63
+ %w(left right).each do |side|
64
+ type_accessor = <<-EOS
65
+ def #{side}_type
66
+ xmi?(#{side}) ? :xmi : :java
67
+ end
68
+ EOS
69
+ class_eval(type_accessor)
70
+ end
71
+ end
72
+
73
+ module Configurator
74
+ class << self
75
+ #########
76
+ protected
77
+
78
+ SIMPLE_TERMS = %w(left right ignore_classes matching_classes)
79
+
80
+ # DSL terms for simple top-level attributes
81
+ SIMPLE_TERMS.each do |attribute|
82
+ simple_setter = <<-EOS
83
+ def #{attribute}(value)
84
+ CaDOVe.#{attribute} = value
85
+ end
86
+ EOS
87
+ class_eval(simple_setter)
88
+ end
89
+ end
90
+ end
91
+ class ConfigurationError < Exception; end
92
+ end
@@ -0,0 +1,5 @@
1
+ require 'rubygems'
2
+
3
+ Dir[File.dirname(__FILE__) + "/models/**/*.rb"].each do |model_file|
4
+ require model_file
5
+ end
@@ -0,0 +1,143 @@
1
+ require 'rexml/document'
2
+ require File.dirname(__FILE__) + '/../helpers'
3
+
4
+ module CaDOVe
5
+ module XMI
6
+ class XMIDocument
7
+ def initialize(input, opts = {})
8
+ opts[:input_type] ||= :file_path
9
+ val =
10
+ if opts[:input_type] == :text
11
+ input
12
+ elsif opts[:input_type] == :file_path
13
+ File.new(input)
14
+ end
15
+
16
+ @xml_doc = REXML::Document.new(val)
17
+ end
18
+
19
+ def classes
20
+ package = UMLPackage.logical_model(@xml_doc) || UMLPackage.all(@xml_doc).first
21
+ raise "No packages found in the XMI document" unless package
22
+ @classes ||= package.classes
23
+ end
24
+
25
+ def hashify
26
+ all = {}
27
+ classes.each do |clazz|
28
+ all.merge!(clazz.hashify)
29
+ end
30
+ all
31
+ end
32
+ end
33
+
34
+ class UMLPackage
35
+ def initialize(xml)
36
+ @xml = xml
37
+ @name = name
38
+ end
39
+
40
+ # def self.logical_model(xml)
41
+ # packages = all(xml)
42
+ # logical = packages.size == 1 ? packages : packages.select{|p| p.name =~ /Logical Model/i}
43
+ # logical.first
44
+ # end
45
+
46
+ def self.all(xml)
47
+ xml.elements.collect('.//UML:Package') do |p|
48
+ new(p)
49
+ end
50
+ end
51
+
52
+ def self.method_missing(name, *args)
53
+ package_name = name.to_s.gsub(/_/, ' ')
54
+ all(args[0]).select{|p| p.name =~ /#{package_name}/i}.first
55
+ end
56
+
57
+ def name
58
+ @name ||= @xml.attributes['name']
59
+ end
60
+
61
+ def classes
62
+ UMLClass.all(@xml)
63
+ end
64
+ end
65
+
66
+ class UMLClass
67
+ def initialize(xml)
68
+ @xml = xml
69
+ end
70
+
71
+ def self.all(xml)
72
+ xml.elements.collect('.//UML:Class') do |c|
73
+ new(c)
74
+ end
75
+ end
76
+
77
+ def name
78
+ @name ||= @xml.attributes['name']
79
+ end
80
+
81
+ def hashify
82
+ field_and_type = attributes.collect{|f| [f.name, f.type] }
83
+ {"#{name}" => field_and_type}
84
+ end
85
+
86
+ def attributes
87
+ @attributes ||= UMLAttribute.all(@xml)
88
+ end
89
+
90
+ def associations
91
+ @associations ||= UMLAssociation.all(@xml, name)
92
+ end
93
+ end
94
+
95
+ class UMLAttribute
96
+ include CaDOVe::Helpers
97
+
98
+ def initialize(xml)
99
+ @xml = xml
100
+ end
101
+
102
+ def self.all(class_element)
103
+ class_element.elements.collect('.//UML:Attribute') do |a|
104
+ new(a)
105
+ end
106
+ end
107
+
108
+ def name
109
+ @name ||= @xml.attributes['name']
110
+ end
111
+
112
+ def type
113
+ @type ||= remove_package_name(REXML::XPath.first(@xml, ".//UML:TaggedValue[@tag='type']").attributes['value'])
114
+ end
115
+
116
+ def key
117
+ "#{name} (#{type})"
118
+ end
119
+ end
120
+
121
+ class UMLAssociation
122
+ def initialize(xml)
123
+ @xml = xml
124
+ end
125
+
126
+ def self.all(class_element, class_name)
127
+ class_element.root.elements.collect("//UML:Association") do |a|
128
+ if REXML::XPath.first(a, ".//UML:TaggedValue[@tag='ea_sourceName']") && REXML::XPath.first(a, ".//UML:TaggedValue[@tag='ea_sourceName']").attributes['value'] == class_name
129
+ new(a)
130
+ end
131
+ end.compact
132
+ end
133
+
134
+ def name
135
+ REXML::XPath.first(@xml, ".//UML:TaggedValue[@tag='ea_targetName']").attributes['value']
136
+ end
137
+
138
+ def key
139
+ "#{name} (#{type})"
140
+ end
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,155 @@
1
+ module CaDOVe
2
+ module Analytics
3
+ class Comparison
4
+ def initialize(left, right, opts={})
5
+ @left = left
6
+ @right = right
7
+ @opts = opts
8
+ end
9
+
10
+ def classes
11
+ @classes ||= ClassMatch.all(@left, @right, @opts)
12
+ end
13
+
14
+ def intersecting_classes
15
+ @intersecting_classes ||= classes.select{|c| c.intersecting_class? }
16
+ end
17
+ end
18
+
19
+ class ClassMatch
20
+ def initialize(key, left_attributes, right_attributes)
21
+ @key = key
22
+ @left_attributes = left_attributes
23
+ @right_attributes = right_attributes
24
+ end
25
+ attr_reader :key
26
+
27
+ # TODO: Clean this mess up
28
+ def self.all(left, right, opts={})
29
+ opts ||= {}
30
+ ignore_classes = opts[:ignore_classes] || []
31
+ matching_classes = opts[:matching_classes] || {}
32
+
33
+ left_keys = left.keys.reject{|k| ignore_classes.include?(k)}
34
+ right_keys = right.keys.reject{|k| ignore_classes.include?(k)}
35
+ ClassMatchKey.align(left_keys, right_keys, matching_classes).collect do |key|
36
+ ClassMatch.new(
37
+ key,
38
+ left["#{key.left}"],
39
+ right["#{key.right}"]
40
+ )
41
+ end
42
+ end
43
+
44
+ def attributes
45
+ @attributes ||= AttributeMatch.all(@left_attributes, @right_attributes)
46
+ end
47
+
48
+ def left_match?
49
+ !@left_attributes.nil?
50
+ end
51
+
52
+ def right_match?
53
+ !@right_attributes.nil?
54
+ end
55
+
56
+ def intersecting_class?
57
+ left_match? && right_match?
58
+ end
59
+ end
60
+
61
+ class ClassMatchKey
62
+ def initialize(left, right)
63
+ @left = left
64
+ @right = right
65
+ end
66
+ attr_reader :left, :right
67
+
68
+ def self.align(left_keys, right_keys, override={})
69
+ override = override.with_indifferent_access
70
+
71
+ matches = []
72
+ left_keys.each do |left_key|
73
+ found =
74
+ if m = override_match(left_key, right_keys, override)
75
+ right_keys.delete(m)
76
+ elsif right_keys.include?(left_key)
77
+ right_keys.delete(left_key)
78
+ end
79
+
80
+ matches << new(left_key, found)
81
+ end
82
+
83
+ right_keys.each do |right_key|
84
+ matches << new(nil, right_key)
85
+ end
86
+
87
+ matches.sort
88
+ end
89
+
90
+ def self.override_match(left_key, right_keys, override={})
91
+ if override.has_key?(left_key) && right_keys.include?(override[left_key].to_s)
92
+ override[left_key].to_s
93
+ elsif override.invert.has_key?(left_key) && right_keys.include?(override.invert[left_key].to_s)
94
+ override.invert[left_key].to_s
95
+ end
96
+ end
97
+
98
+ def <=>(other)
99
+ display <=> other.display
100
+ end
101
+
102
+ def display
103
+ return if left.nil? && right.nil?
104
+
105
+ if left && right.nil?
106
+ left
107
+ elsif right && left.nil?
108
+ right
109
+ elsif left == right
110
+ left
111
+ elsif left != right
112
+ "#{left} => #{right}"
113
+ end
114
+ end
115
+ end
116
+
117
+ class AttributeMatch
118
+ def initialize(name, type, left_match, right_match)
119
+ @name = name
120
+ @type = type
121
+ @left_match = left_match
122
+ @right_match = right_match
123
+ end
124
+
125
+ def self.all(left_attributes, right_attributes)
126
+ combined = (left_attributes | right_attributes).sort{|a,b|a[0] <=> b[0]} # Sort by name
127
+
128
+ combined.collect do |name, type|
129
+ AttributeMatch.new(
130
+ name,
131
+ type,
132
+ left_attributes.include?( [name, type] ),
133
+ right_attributes.include?( [name, type] )
134
+ )
135
+ end
136
+ end
137
+
138
+ def key
139
+ [@name, @type]
140
+ end
141
+
142
+ def left_match?
143
+ @left_match
144
+ end
145
+
146
+ def right_match?
147
+ @right_match
148
+ end
149
+
150
+ def display
151
+ "#{@name} (#{@type})"
152
+ end
153
+ end
154
+ end
155
+ end
@@ -0,0 +1,7 @@
1
+ module CaDOVe
2
+ module Helpers
3
+ def remove_package_name(fully_qualified)
4
+ fully_qualified.sub(/.*\./ , '')
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,149 @@
1
+ # This class has dubious semantics and we only have it so that
2
+ # people can write params[:key] instead of params['key']
3
+ # and they get the same value for both keys.
4
+
5
+ class HashWithIndifferentAccess < Hash
6
+ def initialize(constructor = {})
7
+ if constructor.is_a?(Hash)
8
+ super()
9
+ update(constructor)
10
+ else
11
+ super(constructor)
12
+ end
13
+ end
14
+
15
+ def default(key = nil)
16
+ if key.is_a?(Symbol) && include?(key = key.to_s)
17
+ self[key]
18
+ else
19
+ super
20
+ end
21
+ end
22
+
23
+ alias_method :regular_writer, :[]= unless method_defined?(:regular_writer)
24
+ alias_method :regular_update, :update unless method_defined?(:regular_update)
25
+
26
+ # Assigns a new value to the hash:
27
+ #
28
+ # hash = HashWithIndifferentAccess.new
29
+ # hash[:key] = "value"
30
+ #
31
+ def []=(key, value)
32
+ regular_writer(convert_key(key), convert_value(value))
33
+ end
34
+
35
+ # Updates the instantized hash with values from the second:
36
+ #
37
+ # hash_1 = HashWithIndifferentAccess.new
38
+ # hash_1[:key] = "value"
39
+ #
40
+ # hash_2 = HashWithIndifferentAccess.new
41
+ # hash_2[:key] = "New Value!"
42
+ #
43
+ # hash_1.update(hash_2) # => {"key"=>"New Value!"}
44
+ #
45
+ def update(other_hash)
46
+ other_hash.each_pair { |key, value| regular_writer(convert_key(key), convert_value(value)) }
47
+ self
48
+ end
49
+
50
+ alias_method :merge!, :update
51
+
52
+ # Checks the hash for a key matching the argument passed in:
53
+ #
54
+ # hash = HashWithIndifferentAccess.new
55
+ # hash["key"] = "value"
56
+ # hash.key? :key # => true
57
+ # hash.key? "key" # => true
58
+ #
59
+ def key?(key)
60
+ super(convert_key(key))
61
+ end
62
+
63
+ alias_method :include?, :key?
64
+ alias_method :has_key?, :key?
65
+ alias_method :member?, :key?
66
+
67
+ # Fetches the value for the specified key, same as doing hash[key]
68
+ def fetch(key, *extras)
69
+ super(convert_key(key), *extras)
70
+ end
71
+
72
+ # Returns an array of the values at the specified indices:
73
+ #
74
+ # hash = HashWithIndifferentAccess.new
75
+ # hash[:a] = "x"
76
+ # hash[:b] = "y"
77
+ # hash.values_at("a", "b") # => ["x", "y"]
78
+ #
79
+ def values_at(*indices)
80
+ indices.collect {|key| self[convert_key(key)]}
81
+ end
82
+
83
+ # Returns an exact copy of the hash.
84
+ def dup
85
+ HashWithIndifferentAccess.new(self)
86
+ end
87
+
88
+ # Merges the instantized and the specified hashes together, giving precedence to the values from the second hash
89
+ # Does not overwrite the existing hash.
90
+ def merge(hash)
91
+ self.dup.update(hash)
92
+ end
93
+
94
+ # Performs the opposite of merge, with the keys and values from the first hash taking precedence over the second.
95
+ # This overloaded definition prevents returning a regular hash, if reverse_merge is called on a HashWithDifferentAccess.
96
+ def reverse_merge(other_hash)
97
+ super other_hash.with_indifferent_access
98
+ end
99
+
100
+ def invert
101
+ super.with_indifferent_access
102
+ end
103
+
104
+ # Removes a specified key from the hash.
105
+ def delete(key)
106
+ super(convert_key(key))
107
+ end
108
+
109
+ def stringify_keys!; self end
110
+ def symbolize_keys!; self end
111
+ def to_options!; self end
112
+
113
+ # Convert to a Hash with String keys.
114
+ def to_hash
115
+ Hash.new(default).merge(self)
116
+ end
117
+
118
+ protected
119
+ def convert_key(key)
120
+ key.kind_of?(Symbol) ? key.to_s : key
121
+ end
122
+
123
+ def convert_value(value)
124
+ case value
125
+ when Hash
126
+ value.with_indifferent_access
127
+ when Array
128
+ value.collect { |e| e.is_a?(Hash) ? e.with_indifferent_access : e }
129
+ else
130
+ value
131
+ end
132
+ end
133
+ end
134
+
135
+ module CaDOVe #:nodoc:
136
+ module CoreExtensions #:nodoc:
137
+ module Hash #:nodoc:
138
+ module IndifferentAccess #:nodoc:
139
+ def with_indifferent_access
140
+ hash = HashWithIndifferentAccess.new(self)
141
+ hash.default = self.default
142
+ hash
143
+ end
144
+ end
145
+ end
146
+ end
147
+ end
148
+
149
+ Hash.send(:include, CaDOVe::CoreExtensions::Hash::IndifferentAccess)
@@ -0,0 +1,108 @@
1
+ require 'rjb'
2
+ require File.dirname(__FILE__) + '/../helpers'
3
+
4
+ module CaDOVe
5
+ module Java
6
+ Rjb::load(File.dirname(__FILE__) + '/javalib/qdox-1.10.jar')
7
+
8
+ class JavaSourceTree
9
+ def initialize(directory)
10
+ file = Rjb::import('java.io.File').
11
+ new_with_sig('Ljava.lang.String;', directory)
12
+
13
+ builder = Rjb::import('com.thoughtworks.qdox.JavaDocBuilder').new
14
+ builder._invoke('addSourceTree', 'Ljava.io.File;', file)
15
+
16
+ @sources = builder.getSources
17
+ end
18
+
19
+ def classes
20
+ JavaClass.all(@sources)
21
+ end
22
+
23
+ def hashify
24
+ all = {}
25
+ classes.each do |clazz|
26
+ all.merge!(clazz.hashify)
27
+ end
28
+ all
29
+ end
30
+ end
31
+
32
+ class JavaClass
33
+ def initialize(clazz)
34
+ @clazz = clazz
35
+ end
36
+
37
+ def self.all(sources, including_abstract=false)
38
+ classes = sources.collect { |s| s.getClasses }.flatten
39
+ results = classes.collect { |c| new(c) }
40
+ end
41
+
42
+ def name
43
+ @name ||= @clazz.getName
44
+ end
45
+
46
+ def hashify
47
+ field_and_type = fields.collect{|f| [f.name, f.type] }
48
+ {"#{name}" => field_and_type}
49
+ end
50
+
51
+ def fields
52
+ JavaField.all_non_associated(@clazz)
53
+ end
54
+ alias_method :attributes, :fields
55
+ end
56
+
57
+
58
+ class JavaField
59
+ include CaDOVe::Helpers
60
+ def initialize(field)
61
+ @field = field
62
+ end
63
+
64
+ def self.all(clazz)
65
+ clazz.getFields.collect do |field|
66
+ new(field)
67
+ end.reject{|f| is_constant?(f.name) }
68
+ end
69
+
70
+ def self.all_non_associated(clazz)
71
+ all(clazz).select{|f| is_simple_type(f.type) }
72
+ end
73
+
74
+ def self.is_simple_type(class_name)
75
+ java_lang_and_other = %w(Boolean Byte Character Double Float Integer Long Math Number Short String Date Timestamp)
76
+ primitives = %w(boolean byte char double float integer long short)
77
+ result |= java_lang_and_other.include?(class_name)
78
+ result |= primitives.include?(class_name)
79
+ result
80
+ end
81
+
82
+ def self.is_constant?(name)
83
+ name =~ /^([A-Z]|_)+$/
84
+ end
85
+
86
+ def name
87
+ @name ||= @field.getName
88
+ end
89
+
90
+ def type
91
+ @type ||= remove_package_name(@field.getType.getValue)
92
+ end
93
+
94
+ def ==(other)
95
+ return true if self.equal?(other)
96
+ return false if self.class != Java::JavaMethod
97
+
98
+ if (self.name != other.name)
99
+ return false
100
+ elsif (self.type != other.type)
101
+ return false
102
+ end
103
+
104
+ true
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,60 @@
1
+ # TODO: Move these into a plain text file
2
+ module CaDOVe
3
+ module Reports
4
+ class ClassReport
5
+ def initialize(comparison, left_type, right_type)
6
+ @comparison = comparison
7
+ @left_type = left_type
8
+ @right_type = right_type
9
+ end
10
+
11
+ def display
12
+ puts Time.new.strftime('%b %d, %Y %H:%M:%S %Z')
13
+ puts "\n"
14
+ puts " #{header(@left_type)} | #{header(@right_type)} | Class Name"
15
+ puts "--------------------------------"
16
+ @comparison.classes.each do |clazz|
17
+ puts " #{clazz.left_match? ? 'X' : ' '} | #{clazz.right_match? ? 'X' : ' '} | #{clazz.key.display}"
18
+ end
19
+ end
20
+
21
+ def header(name)
22
+ name.to_s.upcase
23
+ end
24
+ end
25
+
26
+ class AttributeReport
27
+ def initialize(comparison, left_type, right_type)
28
+ @comparison = comparison
29
+ @left_type = left_type
30
+ @right_type = right_type
31
+ end
32
+
33
+ def display
34
+ puts Time.new.strftime('%b %d, %Y %H:%M:%S %Z')
35
+ puts "\n"
36
+
37
+ puts "########################"
38
+ @comparison.intersecting_classes.each do |clazz|
39
+ unless clazz.attributes.empty?
40
+ puts ""
41
+ puts "#{clazz.key.display}"
42
+ puts ""
43
+ puts " #{header(@left_type)} | #{header(@right_type)} | Attributes"
44
+ puts "--------------------------------------"
45
+
46
+ clazz.attributes.each do |a|
47
+ puts " #{a.left_match? ? 'X' : ' '} | #{a.right_match? ? 'X' : ' '} | #{a.display}"
48
+ end
49
+ puts ""
50
+ puts "########################"
51
+ end
52
+ end
53
+ end
54
+
55
+ def header(name)
56
+ name.to_s.upcase
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,18 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe CaDOVe do
4
+ it "should configure the left and right properties" do
5
+ CaDOVe.configure do
6
+ left 'hello'
7
+ right 'world'
8
+ end
9
+
10
+ CaDOVe.left.should == 'hello'
11
+ CaDOVe.right.should == 'world'
12
+ end
13
+
14
+ it "should throws an exception if a required configuration option is accessed without being set" do
15
+ CaDOVe.left = nil
16
+ lambda { CaDOVe.left }.should raise_error(CaDOVe::ConfigurationError)
17
+ end
18
+ end
@@ -0,0 +1,3 @@
1
+ package org.foo;
2
+
3
+ abstract class Animal {}
@@ -0,0 +1,3 @@
1
+ package org.foo;
2
+
3
+ class Cat { }
@@ -0,0 +1,18 @@
1
+ package org.foo;
2
+
3
+ class Dog {
4
+ String color;
5
+ boolean rabid;
6
+ Father father;
7
+ List<Enemies> enemies;
8
+
9
+ public String getColor(){}
10
+ public boolean isRabid(){}
11
+
12
+ public Father getFather() {}
13
+ public List<Enemies> getEnemies() {}
14
+
15
+ public String setIgnoreSetters(){}
16
+ private String getIgnorePrivateMethods(){}
17
+ protected String getIgnoreProtectedMethods(){}
18
+ }
@@ -0,0 +1,127 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
2
+
3
+ module CaDOVe::XMI
4
+ describe UMLClass do
5
+ before(:each) do
6
+ @xmi =
7
+ xmi_document do
8
+ uml_package('Data Model') do
9
+ uml_class('DontFindMe')
10
+ end +
11
+ uml_package('Logical Model') do
12
+ uml_class('Dog') do
13
+ uml_attribute('color', 'String') +
14
+ uml_attribute('rabid', 'boolean')
15
+ end +
16
+ uml_class('Cat')
17
+ end +
18
+
19
+ uml_association('Dog', 'Friend') +
20
+ uml_association('Dog', 'Enemy')
21
+ end
22
+
23
+ @doc = XMIDocument.new(@xmi, :input_type => :text)
24
+ @dog = @doc.classes.select{ |c| c.name == 'Dog' }.first
25
+ end
26
+
27
+ it "should have two classes in the document" do
28
+ classes = @doc.classes
29
+ @doc.should have(2).classes
30
+ end
31
+
32
+ it "should include the class Cat and Dog" do
33
+ names = @doc.classes.collect { |c| c.name }
34
+ names.should include("Cat")
35
+ names.should include("Dog")
36
+ end
37
+
38
+ it "should have the correct attributes for Dog" do
39
+ @dog.should have(2).attributes
40
+ names = @dog.attributes.collect { |c| [c.name, c.type] }
41
+ names.should include( %w(color String) )
42
+ names.should include( %w(rabid boolean) )
43
+ end
44
+
45
+ it "should have the correct correct associations for Dog" do
46
+ @dog.should have(2).associations
47
+ names = @dog.associations.collect { |c| c.name }
48
+ names.should include('Friend')
49
+ names.should include('Enemy')
50
+ end
51
+
52
+ it "should return the only model available if only one exists" do
53
+ single_pkg_xmi =
54
+ xmi_document do
55
+ uml_package('My Package') do
56
+ uml_class('Foo')
57
+ end
58
+ end
59
+
60
+ single_pkg_doc = XMIDocument.new(single_pkg_xmi, :input_type => :text)
61
+ single_pkg_doc.should have(1).classes
62
+ end
63
+
64
+ it "should hashify dog" do
65
+ doggy_hash = @dog.hashify
66
+ doggy_hash['Dog'].should include( %w(color String) )
67
+ doggy_hash['Dog'].should include( %w(rabid boolean) )
68
+ end
69
+
70
+ it "should hashify the document tree" do
71
+ @doc.hashify.keys.should include('Cat')
72
+ @doc.hashify.keys.should include('Dog')
73
+
74
+ @doc.hashify['Dog'].should include( %w(color String) )
75
+ @doc.hashify['Dog'].should include( %w(rabid boolean) )
76
+ end
77
+
78
+ private
79
+ def xmi_document(&block)
80
+ <<-XMI
81
+ <xmi:XMI xmlns:UML="http://schema.omg.org/spec/UML/2.0" xmlns:xmi="http://schema.omg.org/spec/XMI/2.1">
82
+ #{yield if block_given?}
83
+ </xmi:XMI>
84
+ XMI
85
+ end
86
+
87
+ def uml_package(name, &block)
88
+ <<-XMI
89
+ <UML:Package name="#{name}">
90
+ #{yield if block_given?}
91
+ </UML:Package>
92
+ XMI
93
+ end
94
+
95
+ def uml_class(name, &block)
96
+ <<-XMI
97
+ <UML:Class name='#{name}'>
98
+ #{yield if block_given?}
99
+ </UML:Class>
100
+ XMI
101
+ end
102
+
103
+ def uml_attribute(name, type)
104
+ <<-XMI
105
+ <UML:Attribute name='#{name}' visibility='private'>
106
+ <UML:ModelElement.taggedValue>
107
+ <UML:TaggedValue tag='foo' value='bar'/>
108
+ <UML:TaggedValue tag='type' value='#{type}'/>
109
+ <UML:TaggedValue tag='derived' value='0'/>
110
+ </UML:ModelElement.taggedValue>
111
+ </UML:Attribute>
112
+ XMI
113
+ end
114
+
115
+ def uml_association(src, dst)
116
+ <<-XMI
117
+ <UML:Association visibility='public'>
118
+ <UML:ModelElement.taggedValue>
119
+ <UML:TaggedValue tag='style' value='3'/>
120
+ <UML:TaggedValue tag='ea_sourceName' value='#{src}'/>
121
+ <UML:TaggedValue tag='ea_targetName' value='#{dst}'/>
122
+ </UML:ModelElement.taggedValue>
123
+ </UML:Association>
124
+ XMI
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,105 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
2
+
3
+ module CaDOVe::Analytics
4
+ describe Comparison do
5
+ before(:each) do
6
+ @left = {
7
+ 'Dog' => [
8
+ %w(name String),
9
+ %w(rabid boolean)
10
+ ]
11
+ }
12
+
13
+ @right = {
14
+ 'Dog' => [
15
+ %w(name String),
16
+ %w(color String)
17
+ ],
18
+ 'Rabbit' => [ %w(color String) ]
19
+ }
20
+
21
+ @comparison = Comparison.new(@left, @right)
22
+ @dog = @comparison.classes.select{|c| c.key.left == 'Dog' }.first
23
+ end
24
+
25
+ it "should have two class" do
26
+ @comparison.should have(2).classes
27
+ @comparison.classes.collect{|c| [c.key.left, c.key.right]}.should == [
28
+ ['Dog', 'Dog'],
29
+ [nil, 'Rabbit']
30
+ ]
31
+ end
32
+
33
+ it "should have a left and right match" do
34
+ @dog.should be_left_match
35
+ @dog.should be_right_match
36
+ end
37
+
38
+
39
+ it "should have one intersecting class" do
40
+ @comparison.should have(1).intersecting_classes
41
+ @comparison.intersecting_classes.collect{|c| [c.key.left, c.key.right]}.should == [['Dog', 'Dog']]
42
+ end
43
+
44
+ it "should have a dog match with 3 attributes" do
45
+ keys = @dog.attributes.collect{|a| a.key}
46
+ keys.should include( %w(name String) )
47
+ keys.should include( %w(rabid boolean))
48
+ keys.should include( %w(color String) )
49
+ end
50
+
51
+ it "should have a dog match having an 'name' attribute having a left and right match" do
52
+ name = @dog.attributes.select{|a| a.key[0] == 'name'}.first
53
+ name.should be_left_match
54
+ name.should be_right_match
55
+ end
56
+
57
+ it "should have a dog match having an 'rabid' attribute having only a left match" do
58
+ name = @dog.attributes.select{|a| a.key[0] == 'rabid'}.first
59
+ name.should be_left_match
60
+ name.should_not be_right_match
61
+ end
62
+
63
+ it "should ignore the Rabbit class" do
64
+ ignore_on = Comparison.new(@left, @right, :ignore_classes => %w(Rabbit) )
65
+ ignore_on.should have(1).classes
66
+ end
67
+
68
+ it "should manually match 'Rabbit' to 'Hare'" do
69
+ @left['Hare'] = [
70
+ %w(color String)
71
+ ]
72
+
73
+ manual_matching = Comparison.new(@left, @right, :matching_classes => {:Hare => :Rabbit})
74
+ manual_matching.should have(2).intersecting_classes
75
+ names = manual_matching.intersecting_classes.collect{|c| [c.key.left, c.key.right]}
76
+ names.should include(['Hare', 'Rabbit'])
77
+ names.should include(['Dog', 'Dog'])
78
+ end
79
+
80
+ it "should manually match 'Rabbit' to 'Hare' with inverse matching class" do
81
+ @left['Hare'] = [
82
+ %w(color String)
83
+ ]
84
+
85
+ manual_matching = Comparison.new(@left, @right, :matching_classes => {:Rabbit => :Hare})
86
+ manual_matching.should have(2).intersecting_classes
87
+ names = manual_matching.intersecting_classes.collect{|c| [c.key.left, c.key.right]}
88
+ names.should include(['Hare', 'Rabbit'])
89
+ names.should include(['Dog', 'Dog'])
90
+ end
91
+
92
+ it "should align keys" do
93
+ aligned = ClassMatchKey.align(['a', 'b'], ['b', 'c'], :a => :c).collect{|k| [k.left, k.right]}
94
+ aligned.size.should be(2)
95
+ aligned.should include(['b', 'b'])
96
+ aligned.should include(['a', 'c'])
97
+ end
98
+
99
+ it "should sort keys" do
100
+ keys = [ClassMatchKey.new('b', 'b'), ClassMatchKey.new('a', 'a')].sort
101
+ keys[0].left.should == 'a'
102
+ keys[1].left.should == 'b'
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,48 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
2
+
3
+ module CaDOVe::Java
4
+ describe JavaSourceTree do
5
+ before(:each) do
6
+ @code = JavaSourceTree.new(
7
+ File.dirname(__FILE__) + '/../../java_stubs'
8
+ )
9
+
10
+ @dog = @code.classes.select { |c| c.name == "Dog" }.first
11
+ end
12
+
13
+ it "should have three classes in the document" do
14
+ @code.should have(3).classes
15
+ end
16
+
17
+ it "should include only classes Animal, Cat and Dog" do
18
+ names = @code.classes.collect { |c| c.name }
19
+ names.should include("Animal")
20
+ names.should include("Cat")
21
+ names.should include("Dog")
22
+ end
23
+
24
+ it "should have the two fields" do
25
+ @dog.should have(2).fields
26
+ fields = @dog.fields.collect{ |f| [f.name, f.type] }
27
+ fields.should include( %w(color String) )
28
+ fields.should include( %w(rabid boolean) )
29
+ end
30
+
31
+
32
+ it "should hashify Dog" do
33
+ doggy_hash = @dog.hashify
34
+ doggy_hash['Dog'].should include( %w(color String) )
35
+ doggy_hash['Dog'].should include( %w(rabid boolean) )
36
+ end
37
+
38
+ it "should hashify the source tree" do
39
+ @code.hashify.keys.should include('Cat')
40
+ @code.hashify.keys.should include('Dog')
41
+
42
+ @code.hashify['Dog'].should include( %w(color String) )
43
+ @code.hashify['Dog'].should include( %w(rabid boolean) )
44
+ end
45
+
46
+ it "should have only associations"
47
+ end
48
+ end
@@ -0,0 +1 @@
1
+ require File.dirname(__FILE__) + '/../lib/cadove'
metadata ADDED
@@ -0,0 +1,82 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cadove
3
+ version: !ruby/object:Gem::Version
4
+ version: "0.1"
5
+ platform: ruby
6
+ authors:
7
+ - John Dzak
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-02-11 00:00:00 -06:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rjb
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ description:
26
+ email:
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files: []
32
+
33
+ files:
34
+ - lib/cadove/models/analytics/comparison.rb
35
+ - lib/cadove/models/helpers.rb
36
+ - lib/cadove/models/indifferent_access.rb
37
+ - lib/cadove/models/java/code.rb
38
+ - lib/cadove/models/java/javalib/qdox-1.10.jar
39
+ - lib/cadove/models/reports/reports.rb
40
+ - lib/cadove/models/XMI/document.rb
41
+ - lib/cadove/models.rb
42
+ - lib/cadove.rb
43
+ - CHANGELOG
44
+ - README
45
+ - spec/cadove_spec.rb
46
+ - spec/java_stubs/org/foo/Animal.java
47
+ - spec/java_stubs/org/foo/Cat.java
48
+ - spec/java_stubs/org/foo/Dog.java
49
+ - spec/models/analytics/comparison_spec.rb
50
+ - spec/models/java/code_spec.rb
51
+ - spec/models/XMI/document_spec.rb
52
+ - spec/spec_helper.rb
53
+ has_rdoc: true
54
+ homepage:
55
+ licenses: []
56
+
57
+ post_install_message:
58
+ rdoc_options: []
59
+
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: "0"
67
+ version:
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: "0"
73
+ version:
74
+ requirements: []
75
+
76
+ rubyforge_project:
77
+ rubygems_version: 1.3.5
78
+ signing_key:
79
+ specification_version: 3
80
+ summary: Domain Object Verifier compares Java domain objects to their corresponding XMI representations.
81
+ test_files: []
82
+