archruby 0.2.0 → 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.
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]