archruby 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +3 -0
  3. data/README.md +1 -1
  4. data/Rakefile +46 -0
  5. data/TODO.rtf +20 -0
  6. data/architecture.yml +51 -0
  7. data/archruby.gemspec +3 -0
  8. data/bin/archruby +1 -0
  9. data/lib/archruby.rb +14 -2
  10. data/lib/archruby/architecture/architecture.rb +6 -6
  11. data/lib/archruby/architecture/config_definition.rb +13 -13
  12. data/lib/archruby/architecture/constraint_break.rb +1 -1
  13. data/lib/archruby/architecture/dependency.rb +3 -1
  14. data/lib/archruby/architecture/file_content.rb +2 -2
  15. data/lib/archruby/architecture/module_definition.rb +33 -20
  16. data/lib/archruby/architecture/parser.rb +25 -11
  17. data/lib/archruby/architecture/type_inference_checker.rb +29 -13
  18. data/lib/archruby/presenters/dsm.rb +163 -0
  19. data/lib/archruby/presenters/dsm/cell_dsm.rb +17 -0
  20. data/lib/archruby/presenters/dsm/dsm_css.css +77 -0
  21. data/lib/archruby/presenters/graph.rb +12 -9
  22. data/lib/archruby/ruby/parser.rb +131 -125
  23. data/lib/archruby/ruby/type_inference/dependency_organizer.rb +53 -0
  24. data/lib/archruby/ruby/type_inference/ruby/class_dependency.rb +22 -0
  25. data/lib/archruby/ruby/type_inference/ruby/internal_method_invocation.rb +20 -0
  26. data/lib/archruby/ruby/type_inference/ruby/method_definition.rb +20 -0
  27. data/lib/archruby/ruby/type_inference/ruby/parser_for_typeinference.rb +537 -0
  28. data/lib/archruby/ruby/type_inference/ruby/process_method_arguments.rb +155 -0
  29. data/lib/archruby/ruby/type_inference/ruby/process_method_body.rb +427 -0
  30. data/lib/archruby/ruby/type_inference/ruby/process_method_params.rb +276 -0
  31. data/lib/archruby/ruby/type_inference/type_inference_checker.rb +126 -0
  32. data/lib/archruby/version.rb +1 -1
  33. data/spec/architecture/file_content_spec.rb +2 -1
  34. data/spec/architecture/module_definition_spec.rb +9 -9
  35. data/spec/dummy_app/lib/teste_class.rb +6 -0
  36. data/spec/ruby/type_inference/dependency_organizer_spec.rb +20 -0
  37. data/spec/ruby/type_inference/fixtures/homebrew_bottles_class.rb +139 -0
  38. data/spec/ruby/type_inference/fixtures/homebrew_brew_teste.rb +1323 -0
  39. data/spec/ruby/type_inference/fixtures/rails_action_view_class_teste.rb +89 -0
  40. data/spec/ruby/type_inference/fixtures/rails_active_record_class.rb +99 -0
  41. data/spec/ruby/type_inference/fixtures/rails_teste_active_record.rb +55 -0
  42. data/spec/ruby/type_inference/fixtures/teste2.rb +16 -0
  43. data/spec/ruby/type_inference/fixtures/teste_class_and_args.rb +49 -0
  44. data/spec/ruby/type_inference/fixtures/teste_class_and_args2.rb +11 -0
  45. data/spec/ruby/type_inference/parser_for_typeinference_spec.rb +69 -0
  46. data/spec/ruby/type_inference/type_inference_checker_spec.rb +47 -0
  47. metadata +84 -3
@@ -6,11 +6,12 @@ module Archruby
6
6
  class Parser
7
7
  attr_reader :modules
8
8
 
9
- def initialize config_file_path, base_path
9
+ def initialize(config_file_path, base_path)
10
10
  @config_file = config_file_path
11
11
  @base_path = base_path
12
12
  @modules = []
13
13
  @type_inference_checker = TypeInferenceChecker.new
14
+ @type_inferece_dependency_organizer = Archruby::Ruby::TypeInference::DependencyOrganizer.new
14
15
  parse
15
16
  ruby_std_lib_module
16
17
  ruby_core_module
@@ -18,21 +19,34 @@ module Archruby
18
19
  end
19
20
 
20
21
  def parse
21
- parsed_yaml = yaml_parser.load_file @config_file
22
+ parsed_yaml = yaml_parser.load_file(@config_file)
22
23
  parsed_yaml.each do |module_name, definitions|
23
24
  begin
24
- config_definition = Archruby::Architecture::ConfigDefinition.new module_name, definitions
25
- module_definition = Archruby::Architecture::ModuleDefinition.new config_definition, @base_path
26
- @type_inference_checker.add_method_deps module_definition.class_methods_and_deps
27
- @type_inference_checker.add_method_calls module_definition.class_methods_calls
25
+ config_definition = Archruby::Architecture::ConfigDefinition.new(module_name, definitions)
26
+ module_definition = Archruby::Architecture::ModuleDefinition.new(config_definition, @base_path)
27
+ # @type_inference_checker.add_method_deps(module_definition.class_methods_and_deps)
28
+ # @type_inference_checker.add_method_calls(module_definition.class_methods_calls)
29
+
30
+ @type_inferece_dependency_organizer.add_dependencies(module_definition.type_inference_dependencies)
31
+ @type_inferece_dependency_organizer.add_method_calls(module_definition.type_inference_methods_calls)
28
32
  rescue Archruby::MultipleConstraints => e
29
33
  STDOUT.puts "The config file is not right: #{e.msg} | err_code: #{e.status_code} | module_definition: #{module_name}"
30
34
  exit(e.status_code)
31
35
  end
32
36
  @modules << module_definition
33
- @type_inference_checker.verify_types
34
- @type_inference_checker.add_new_deps @modules
37
+ #binding.pry
38
+ # @type_inference_checker.verify_types
39
+ # @type_inference_checker.add_new_deps(@modules)
35
40
  end
41
+ type_inferece_verifier = Archruby::Ruby::TypeInference::TypeInferenceChecker.new(
42
+ @type_inferece_dependency_organizer.dependencies,
43
+ @type_inferece_dependency_organizer.method_definitions
44
+ )
45
+ type_inferece_verifier.add_dependency_based_on_calls
46
+ type_inferece_verifier.add_dependency_based_on_internal_calls
47
+ @type_inference_checker.populate_dependencies(type_inferece_verifier.dependencies)
48
+ @type_inference_checker.add_new_deps(@modules)
49
+ #binding.pry
36
50
  end
37
51
 
38
52
  def yaml_parser
@@ -40,21 +54,21 @@ module Archruby
40
54
  end
41
55
 
42
56
  def ruby_std_lib_module
43
- config_definition_std_lib = Archruby::Architecture::ConfigDefinition.new Archruby::Ruby::STD_LIB_NAME, {"gems"=>"", "files"=>"", "allowed"=>"", "forbidden" => ""}
57
+ config_definition_std_lib = Archruby::Architecture::ConfigDefinition.new(Archruby::Ruby::STD_LIB_NAME, {"gems"=>"", "files"=>"", "allowed"=>"", "forbidden" => ""})
44
58
  module_definiton_std_lib = Archruby::Architecture::ModuleDefinition.new(config_definition_std_lib, @base_path)
45
59
  module_definiton_std_lib.classes = Archruby::Ruby::STD_LIBRARY_CLASSES
46
60
  @modules << module_definiton_std_lib
47
61
  end
48
62
 
49
63
  def ruby_core_module
50
- config_definition_core = Archruby::Architecture::ConfigDefinition.new Archruby::Ruby::CORE_LIB_NAME, {"gems"=>"", "files"=>"", "allowed"=>"", "forbidden" => ""}
64
+ config_definition_core = Archruby::Architecture::ConfigDefinition.new(Archruby::Ruby::CORE_LIB_NAME, {"gems"=>"", "files"=>"", "allowed"=>"", "forbidden" => ""})
51
65
  module_definiton_core = Archruby::Architecture::ModuleDefinition.new(config_definition_core, @base_path)
52
66
  module_definiton_core.classes = Archruby::Ruby::CORE_LIBRARY_CLASSES
53
67
  @modules << module_definiton_core
54
68
  end
55
69
 
56
70
  def unknow_module
57
- config_definition_unknow = Archruby::Architecture::ConfigDefinition.new "unknown", {"gems"=>"unknown", "files"=>"", "allowed"=>"", "forbidden" => ""}
71
+ config_definition_unknow = Archruby::Architecture::ConfigDefinition.new("unknown", {"gems"=>"unknown", "files"=>"", "allowed"=>"", "forbidden" => ""})
58
72
  @modules << Archruby::Architecture::ModuleDefinition.new(config_definition_unknow, @base_path)
59
73
  end
60
74
 
@@ -2,35 +2,51 @@ module Archruby
2
2
  module Architecture
3
3
 
4
4
  class TypeInferenceChecker
5
- attr_reader :method_and_deps, :method_calls
5
+ #attr_reader :method_and_deps, :method_calls
6
+ attr_reader :dependencies
6
7
 
7
- def initialize method_and_deps = nil, method_calls = nil
8
- @method_and_deps = []
9
- @method_calls = []
10
- @method_and_deps = method_and_deps unless method_and_deps.nil?
11
- @method_calls = method_calls unless method_calls.nil?
8
+ def initialize(dependencies=nil)
9
+ @dependencies = dependencies
10
+ # @method_and_deps = []
11
+ # @method_calls = []
12
+ # @method_and_deps = method_and_deps unless method_and_deps.nil?
13
+ # @method_calls = method_calls unless method_calls.nil?
12
14
  end
13
15
 
14
- def add_method_deps method_deps
16
+ def populate_dependencies(dependencies)
17
+ @dependencies = dependencies
18
+ end
19
+
20
+ def add_method_deps(method_deps)
15
21
  @method_and_deps << method_deps
16
22
  @method_and_deps.flatten!
17
23
  end
18
24
 
19
- def add_method_calls method_calls
25
+ def add_method_calls(method_calls)
20
26
  @method_calls << method_calls
21
27
  @method_calls.flatten!
22
28
  end
23
29
 
24
- def add_new_deps modules
25
- @method_and_deps.each do |dep|
30
+ def add_new_deps(modules)
31
+ @dependencies.each do |klass, dependencies|
26
32
  modules.each do |modl|
27
- if !dep[:class_name].nil? && modl.is_mine?(dep[:class_name])
28
- dep[:dep].each do |class_dep|
29
- modl.add_new_dep dep[:class_name], class_dep
33
+ if !klass.nil? && modl.is_mine?(klass)
34
+ dependencies.each do |class_dep_name|
35
+ modl.add_new_dep(klass, class_dep_name)
30
36
  end
31
37
  end
32
38
  end
33
39
  end
40
+ # @method_and_deps.each do |dep|
41
+ # modules.each do |modl|
42
+ # if !dep[:class_name].nil? && modl.is_mine?(dep[:class_name])
43
+ # dep[:dep].each do |class_dep|
44
+ # modl.add_new_dep(dep[:class_name], class_dep)
45
+ # binding.pry
46
+ # end
47
+ # end
48
+ # end
49
+ # end
34
50
  end
35
51
 
36
52
  def verify_types
@@ -0,0 +1,163 @@
1
+ require 'imgkit'
2
+ require_relative 'dsm/cell_dsm'
3
+
4
+ module Archruby
5
+ module Presenters
6
+
7
+ class DSM
8
+
9
+ def render(architecture)
10
+ matrix = create_DSM(architecture)
11
+ html = create_HTML(getModules(architecture), matrix)
12
+ save_img(html)
13
+ end
14
+
15
+ def save_img(html)
16
+ path_css = File.expand_path('../dsm/dsm_css.css', __FILE__)
17
+ path_img = File.absolute_path("architecture_dsm.png")
18
+ kit = IMGKit.new(html, :quality => 100)
19
+ kit.stylesheets << path_css
20
+ kit.to_file(path_img)
21
+ end
22
+
23
+ def create_DSM(architecture)
24
+ modules = getModules(architecture)
25
+ index = create_hash_index(modules)
26
+ matrix = Array.new(modules.size) { Array.new(modules.size) }
27
+
28
+
29
+ #adiciona na matriz todas as dependências permitidas
30
+ modules.each do |module_definiton|
31
+ module_name = module_definiton.name
32
+ dependencies = []
33
+ module_definiton.dependencies.each do |class_name|
34
+ module_dest = architecture.module_name(class_name)
35
+ dependencies << module_dest
36
+ next if module_dest == Archruby::Ruby::STD_LIB_NAME || module_dest == Archruby::Ruby::CORE_LIB_NAME
37
+ next if module_dest == 'unknown'
38
+ how_many_access = architecture.how_many_access_to(module_name, module_dest)
39
+ if module_dest != module_name
40
+ matrix[index[module_dest]][index[module_name]] = CellDSM.new(how_many_access, "allowed")
41
+ end
42
+ end
43
+ module_definiton.allowed_modules.each do |allowed_module_name|
44
+ if !dependencies.include? allowed_module_name
45
+ matrix[index[allowed_module_name]][index[module_name]] = CellDSM.new("?","warning")
46
+ end
47
+ end
48
+ end
49
+
50
+ #adiciona na matriz todas as violações
51
+ constraints_breaks = architecture.constraints_breaks
52
+ constraints_breaks.each do |constraint_break|
53
+ module_origin = constraint_break.module_origin
54
+ module_target = constraint_break.module_target
55
+ contraint_type = constraint_break.type
56
+ how_many_access =
57
+ if contraint_type == Archruby::Architecture::ConstraintBreak::ABSENSE
58
+ architecture.how_many_break(module_origin, module_target, Archruby::Architecture::ConstraintBreak::ABSENSE)
59
+ else
60
+ architecture.how_many_break(module_origin, module_target, Archruby::Architecture::ConstraintBreak::DIVERGENCE)
61
+ end
62
+ begin
63
+ matrix[index[module_target]][index[module_origin]] = CellDSM.new(how_many_access,contraint_type)
64
+ rescue
65
+ end
66
+
67
+ end
68
+ matrix
69
+ end
70
+
71
+ def font(number)
72
+ font =
73
+ if number >= 1000
74
+ "<font size = '1'>#{number}<font>"
75
+ elsif number >= 100
76
+ "<font size = '2'>#{number}<font>"
77
+ else
78
+ "#{number}"
79
+ end
80
+ font
81
+ end
82
+
83
+ def create_HTML(modules, matrix)
84
+ show_unknown = show_unknown?(matrix, modules)
85
+ text = "\n<center><table>\n"
86
+ text = "#{text} <tr>\n"
87
+ text = "#{text} <th>Modules</th>\n"
88
+ for i in 0..modules.size - 1
89
+ next if modules[i].name == 'unknown' && !show_unknown
90
+ module_type = modules[i].is_external? ? "external" : "internal"
91
+ text = "#{text} <td class='#{module_type}'><div style='width: 25px'><center>#{font(i+1)}</center></div></td>\n"
92
+ end
93
+ text = "#{text} </tr>\n"
94
+ for line in 0..matrix.size - 1
95
+ next if modules[line].name == 'unknown' && !show_unknown
96
+ text = "#{text} <tr>\n"
97
+ module_type = modules[line].is_external? ? "external" : "internal"
98
+ text = "#{text} <td class='#{module_type}'><div class='module'>#{modules[line].name}</div><div class='number'>#{line+1}</div></td>\n"
99
+ for column in 0..matrix.size - 1
100
+ next if modules[column].name == 'unknown' && !show_unknown
101
+ text =
102
+ if line == column
103
+ "#{text} <td class='diagonal'></td>\n"
104
+ elsif matrix[line][column].nil?
105
+ "#{text} <td class='default'></td>\n"
106
+ elsif matrix[line][column].type == "absence"
107
+ "#{text} <td class='absence'><center>#{font(matrix[line][column].how_many_access)}</center></td>\n"
108
+ elsif matrix[line][column].type == "divergence"
109
+ "#{text} <td class='divergence'><center>#{font(matrix[line][column].how_many_access)}</center></td>\n"
110
+ elsif matrix[line][column].type == "warning"
111
+ "#{text} <td class='warning'><center>#{matrix[line][column].how_many_access}</center></td>\n"
112
+ else
113
+ "#{text} <td class='default'><center>#{font(matrix[line][column].how_many_access)}</center></td>\n"
114
+ end
115
+ end
116
+ text = "#{text} </tr>\n"
117
+ end
118
+ text = "#{text}</table> </center>"
119
+ text
120
+ end
121
+
122
+ def getModules(architecture)
123
+ modules = []
124
+ architecture.modules.each do |module_definiton|
125
+ #next if module_definiton.name == 'unknown'
126
+ next if module_definiton.name == Archruby::Ruby::STD_LIB_NAME || module_definiton.name == Archruby::Ruby::CORE_LIB_NAME
127
+ modules << module_definiton
128
+ end
129
+ modules
130
+ end
131
+
132
+ def create_hash_index(modules)
133
+ index = {}
134
+ for i in 0..modules.size - 1
135
+ index[modules[i].name] = i
136
+ end
137
+ index
138
+ end
139
+
140
+ def show_unknown?(matrix, modules)
141
+ #column = column of module unknown
142
+ column = -1
143
+ show_unknown = false
144
+ for i in 0 .. modules.size - 1
145
+ if modules[i].name == 'unknown'
146
+ column = i
147
+ break
148
+ end
149
+ end
150
+ if column != -1
151
+ for i in 0 .. matrix.size - 1
152
+ if !matrix[i][column].nil? || !matrix[column][i].nil?
153
+ show_unknown = true
154
+ break
155
+ end
156
+ end
157
+ end
158
+ show_unknown
159
+ end
160
+
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,17 @@
1
+ module Archruby
2
+ module Presenters
3
+
4
+ class CellDSM
5
+
6
+ attr_reader :type
7
+ attr_reader :how_many_access
8
+
9
+ def initialize(how_many_access, type)
10
+ @how_many_access = how_many_access
11
+ @type = type
12
+ end
13
+
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,77 @@
1
+ table td, tr, th {
2
+ margin:0;
3
+ padding:0;
4
+ font-weight:normal;
5
+ }
6
+
7
+ table td,th {
8
+ padding:5px;
9
+ border:1px solid #fff;
10
+ border-width:0 1px 1px 0;
11
+ }
12
+
13
+ table {
14
+ white-space: nowrap;
15
+ border-collapse:collapse;
16
+ margin-bottom:15px;
17
+ }
18
+
19
+ td,th {
20
+ text-align:center;
21
+ }
22
+
23
+ th {
24
+ background:#F9F9F9;
25
+ }
26
+
27
+ .absence{
28
+ width:25px;
29
+ background:rgba(255,0,0,0.4);
30
+ border: 2px double #ff0000;
31
+ padding: 2px;
32
+ border-style:dotted;
33
+ }
34
+
35
+ .divergence{
36
+ width:25px;
37
+ background:rgba(255,162,0,0.4);
38
+ border: 2px double #ffa200;
39
+ padding: 2px;
40
+ border-style:dashed;
41
+ }
42
+
43
+ .diagonal{
44
+ width:25px;
45
+ background:#F3F3F3;
46
+ }
47
+
48
+ .external{
49
+ background:#999999;
50
+ }
51
+
52
+ .internal{
53
+ background:#ebebeb;
54
+ }
55
+
56
+ .default{
57
+ width:25px;
58
+ background:#F9F9F9;
59
+ }
60
+
61
+ .module{
62
+ float: left;
63
+ padding-right: 5px;
64
+ }
65
+
66
+ .number{
67
+ float: right;
68
+ }
69
+
70
+ .warning{
71
+ border: 1px double gray;
72
+ width:25px;
73
+ background:#F9F9F9;
74
+ font-size: 12;
75
+ color: gray;
76
+ text-align: center;
77
+ }
@@ -23,6 +23,7 @@ module Archruby
23
23
  internal_nodes = []
24
24
  external_nodes = []
25
25
  modules.each do |module_definiton|
26
+ next if module_definiton.name == 'unknown'
26
27
  next if module_definiton.name == Archruby::Ruby::STD_LIB_NAME || module_definiton.name == Archruby::Ruby::CORE_LIB_NAME
27
28
  if module_definiton.is_external?
28
29
  nodes[module_definiton.name] = external.add_nodes(module_definiton.name, "shape" => "parallelogram", "color" => "gray60", "style" => "filled")
@@ -49,6 +50,7 @@ module Archruby
49
50
  module_definiton.dependencies.each do |class_name|
50
51
  module_dest = architecture.module_name class_name
51
52
  next if module_dest == Archruby::Ruby::STD_LIB_NAME || module_dest == Archruby::Ruby::CORE_LIB_NAME
53
+ next if module_dest == 'unknown'
52
54
  how_many_access = architecture.how_many_access_to module_name, module_dest
53
55
  if !edges[module_name][:edges].include?(module_dest) && module_dest != module_name
54
56
  edges[module_name][:edges] << module_dest
@@ -62,6 +64,7 @@ module Archruby
62
64
  constraints_breaks.each_with_index do |constraint_break, index|
63
65
  module_origin = constraint_break.module_origin
64
66
  module_target = constraint_break.module_target
67
+ next if module_target == 'unknown'
65
68
  contraint_type = constraint_break.type
66
69
  node_origin = nodes[module_origin]
67
70
  node_dest = nodes[module_target]
@@ -72,14 +75,14 @@ module Archruby
72
75
  edge.set do |e|
73
76
  e.headlabel = "X (##{architecture.how_many_break(module_origin, module_target, Archruby::Architecture::ConstraintBreak::ABSENSE)})"
74
77
  e.color = "red"
75
- e.style = "bold"
78
+ e.style = "dotted"
76
79
  e.minlen = 2
77
80
  end
78
81
  else
79
82
  edge.set do |e|
80
83
  e.headlabel = "! (##{architecture.how_many_break(module_origin, module_target, Archruby::Architecture::ConstraintBreak::DIVERGENCE)})"
81
84
  e.color = "orange"
82
- e.style = "bold"
85
+ e.style = "dashed"
83
86
  e.minlen = 2
84
87
  end
85
88
  end
@@ -91,10 +94,10 @@ module Archruby
91
94
  if !node_found
92
95
  if contraint_type == Archruby::Architecture::ConstraintBreak::ABSENSE
93
96
  break_count = architecture.how_many_break(module_origin, module_target, Archruby::Architecture::ConstraintBreak::ABSENSE)
94
- edges_objs << g.add_edges(node_origin, node_dest, :color => 'red', :headlabel => "X (##{break_count})", 'style' => 'bold', :minlen => 2)
97
+ edges_objs << g.add_edges(node_origin, node_dest, :color => 'red', :headlabel => "X (##{break_count})", 'style' => 'dotted', :minlen => 2)
95
98
  else
96
99
  break_count = architecture.how_many_break(module_origin, module_target, Archruby::Architecture::ConstraintBreak::DIVERGENCE)
97
- edges_objs << g.add_edges(node_origin, node_dest, :color => 'red', :headlabel => "! (##{break_count})", 'style' => 'bold', :minlen => 2)
100
+ edges_objs << g.add_edges(node_origin, node_dest, :color => 'orange', :headlabel => "! (##{break_count})", 'style' => 'dashed', :minlen => 2)
98
101
  end
99
102
  end
100
103
  end
@@ -103,11 +106,11 @@ module Archruby
103
106
  next if module_definiton.name == Archruby::Ruby::STD_LIB_NAME || module_definiton.name == Archruby::Ruby::CORE_LIB_NAME
104
107
  module_origin = module_definiton.is_empty? ? "#{module_definiton.name}\n [empty]" : module_definiton.name
105
108
  node_origin = nodes[module_origin]
106
- puts module_definiton.name.inspect
107
- puts module_definiton.classes.inspect
108
- puts module_definiton.dependencies.inspect
109
- puts module_definiton.classes_and_dependencies.inspect
110
- puts
109
+ # puts module_definiton.name.inspect
110
+ # puts module_definiton.classes.inspect
111
+ # puts module_definiton.dependencies.inspect
112
+ # puts module_definiton.classes_and_dependencies.inspect
113
+ # puts
111
114
  module_definiton.allowed_modules.each do |allowed_module_name|
112
115
  module_target = allowed_module_name
113
116
  node_dest = nodes[allowed_module_name]