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
@@ -0,0 +1,276 @@
1
+ module Archruby
2
+ module Ruby
3
+ module TypeInference
4
+ module Ruby
5
+
6
+ class ProcessMethodParams < SexpInterpreter
7
+ def initialize(ast, local_scope)
8
+ super()
9
+ @ast = ast
10
+ @current_dependency_class = []
11
+ @current_dependency_class_name = nil
12
+ @local_scope = local_scope
13
+ @params = []
14
+ end
15
+
16
+ def parse
17
+ @ast.map! {|sub_tree| process(sub_tree)}
18
+ @params
19
+ end
20
+
21
+ def process_defn(exp)
22
+ #estudar esse caso
23
+ end
24
+
25
+ def process_dregx_once(exp)
26
+ _, start, *args = exp
27
+ args.map! {|sub_tree| process(sub_tree) if sub_tree.class == Sexp}
28
+ end
29
+
30
+ def process_block(exp)
31
+ _, *args = exp
32
+ args.map! { |subtree| process(subtree) }
33
+ end
34
+
35
+ def process_kwsplat(exp)
36
+ _, *args = exp
37
+ args.map! { |subtree| process(subtree) }
38
+ end
39
+
40
+ def process_dot3(exp)
41
+ _, left, right = exp
42
+ process(left)
43
+ process(right)
44
+ end
45
+
46
+ def process_lasgn(exp)
47
+ end
48
+
49
+ def process_lvar(exp)
50
+ _, lvar_name = exp
51
+ type = @local_scope.var_type(lvar_name)
52
+ if type
53
+ add_to_params(type)
54
+ else
55
+ add_to_params(lvar_name)
56
+ end
57
+ #chamado para pegar o valor
58
+ end
59
+
60
+ def process_const(exp)
61
+ _, const_name = exp
62
+ if !@current_dependency_class.empty?
63
+ @current_dependency_class_name = build_full_name(const_name)
64
+ add_to_params(@current_dependency_class_name)
65
+ @current_dependency_class_name = nil
66
+ else
67
+ add_to_params(const_name)
68
+ end
69
+ end
70
+
71
+ def process_call(exp)
72
+ _, receiver, method_name, *params = exp
73
+ process(receiver)
74
+ end
75
+
76
+ def process_block_pass(exp)
77
+ _, *args = exp
78
+ args.map! { |subtree| process(subtree) }
79
+ end
80
+
81
+ def add_to_params(name)
82
+ @params << name
83
+ end
84
+
85
+ def process_colon2(exp)
86
+ _, first_part, last_part = exp
87
+ @current_dependency_class.unshift(last_part)
88
+ process(first_part)
89
+ end
90
+
91
+ def process_colon3(exp)
92
+ _, constant_name = exp
93
+ @current_dependency_class_name = build_full_name("::#{constant_name}")
94
+ end
95
+
96
+ def build_full_name(const_name)
97
+ @current_dependency_class.unshift(const_name)
98
+ full_class_path = @current_dependency_class.join('::')
99
+ @current_dependency_class = []
100
+ full_class_path
101
+ end
102
+
103
+ def process_hash(exp)
104
+ _, key, value = exp
105
+ process(key)
106
+ process(value)
107
+ end
108
+
109
+ def process_splat(exp)
110
+ _, *args = exp
111
+ args.map! {|sub_tree| process(sub_tree)}
112
+ end
113
+
114
+ def process_iasgn(exp)
115
+ _, instance_varialbe_name, *value = exp
116
+ value.map! { |subtree| process(subtree) }
117
+ end
118
+
119
+ def process_if(exp)
120
+ _, condition, true_body, else_body = exp
121
+ process(condition)
122
+ process(true_body)
123
+ process(else_body)
124
+ end
125
+
126
+ def process_iter(exp)
127
+ _, first_part, second_part, *body = exp
128
+ process(first_part)
129
+ body.map! {|sub_tree| process(sub_tree)}
130
+ end
131
+
132
+ def process_dstr(exp)
133
+ _, init, *args = exp
134
+ args.map! {|sub_tree| process(sub_tree)}
135
+ end
136
+
137
+ def process_evstr(exp)
138
+ _, *args = exp
139
+ args.map! {|sub_tree| process(sub_tree)}
140
+ end
141
+
142
+ def process_xstr(exp)
143
+ end
144
+
145
+ def process_array(exp)
146
+ _, *elements = exp
147
+ elements.map! {|sub_tree| process(sub_tree)}
148
+ end
149
+
150
+ def process_match2(exp)
151
+ _, rec, *args = exp
152
+ args.map! {|sub_tree| process(sub_tree)}
153
+ end
154
+
155
+ def process_defined(exp)
156
+ _, *args = exp
157
+ args.map! {|sub_tree| process(sub_tree)}
158
+ end
159
+
160
+ def process_dxstr(exp)
161
+ _, str, *args = exp
162
+ args.map! {|sub_tree| process(sub_tree)}
163
+ end
164
+
165
+ def process_dregx(exp)
166
+ _, str, *args = exp
167
+ args.map! {|sub_tree| process(sub_tree) if sub_tree.class == Sexp }
168
+ end
169
+
170
+ def process_dot2(exp)
171
+ _, left, right = exp
172
+ process(left)
173
+ process(right)
174
+ end
175
+
176
+ def process_dsym(exp)
177
+ _, str, *args = exp
178
+ args.map! {|sub_tree| process(sub_tree)}
179
+ end
180
+
181
+ def process_or(exp)
182
+ _, left_side, right_side = exp
183
+ process(left_side)
184
+ process(right_side)
185
+ end
186
+
187
+ def process_and(exp)
188
+ _, left_side, right_side = exp
189
+ process(left_side)
190
+ process(right_side)
191
+ end
192
+
193
+ def process_case(exp)
194
+ _, condition, when_part, ensure_part = exp
195
+ process(condition)
196
+ process(when_part)
197
+ process(ensure_part)
198
+ end
199
+
200
+ def process_when(exp)
201
+ _, condition, body = exp
202
+ process(condition)
203
+ process(body)
204
+ end
205
+
206
+ def process_rescue(exp)
207
+ _, body, rescbody = exp
208
+ process(body)
209
+ process(rescbody)
210
+ end
211
+
212
+ def process_attrasgn(exp)
213
+ _, receiver, method, arg, value = exp
214
+ process(receiver)
215
+ process(value)
216
+ end
217
+
218
+ def process_yield(exp)
219
+ _, *args = exp
220
+ args.map! {|sub_tree| process(sub_tree)}
221
+ end
222
+
223
+ def process_match3(exp)
224
+ _, first, second = exp
225
+ process(first)
226
+ process(second)
227
+ end
228
+
229
+ def process_nth_ref(exp)
230
+ end
231
+
232
+ def process_gvar(exp)
233
+ end
234
+
235
+ def process_back_ref(exp)
236
+ end
237
+
238
+ def process_lit(exp)
239
+ _, value = exp
240
+ end
241
+
242
+ def process_cvar(exp)
243
+ # class variable
244
+ end
245
+
246
+ def process_super(exp)
247
+ end
248
+
249
+ def process_nil(exp)
250
+ end
251
+
252
+ def process_self(exp)
253
+ end
254
+
255
+ def process_str(exp)
256
+ end
257
+
258
+ def process_false(exp)
259
+ end
260
+
261
+ def process_true(exp)
262
+ end
263
+
264
+ def process_ivar(exp)
265
+ end
266
+
267
+ def process_zsuper(exp)
268
+ end
269
+
270
+
271
+ end
272
+
273
+ end
274
+ end
275
+ end
276
+ end
@@ -0,0 +1,126 @@
1
+ module Archruby
2
+ module Ruby
3
+ module TypeInference
4
+
5
+ class TypeInferenceChecker
6
+ attr_reader :dependencies, :method_definitions
7
+
8
+ def initialize(dependencies, method_definitions)
9
+ @dependencies = dependencies
10
+ @method_definitions = method_definitions
11
+ end
12
+
13
+ def total_deps
14
+ total_dep = 0
15
+ @dependencies.each do |class_name, deps|
16
+ total_dep += deps.size
17
+ end
18
+ total_dep
19
+ end
20
+
21
+ def add_dependency_based_on_calls
22
+ @method_definitions.each do |class_name, method_definitions|
23
+ method_definitions.each do |method_definition|
24
+ method_definition.method_calls.each do |method_call|
25
+ receiver_class = method_call.class_name
26
+ method_name = method_call.method_name
27
+ dependencies = extract_param_classes(method_definition.args, method_call.params)
28
+ add_new_dependencies(receiver_class, dependencies, method_name)
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ def add_dependency_based_on_internal_calls
35
+ 3.times do
36
+ @method_definitions.each do |class_name, method_definitions|
37
+ method_definitions.each do |method_definition|
38
+ method_definition.method_calls.each do |method_call|
39
+ receiver_class = method_call.class_name
40
+ method_name = method_call.method_name
41
+ formal_params = extract_formal_parameter(method_call.params)
42
+ dependencies = extract_param_classes(method_definition.args, formal_params)
43
+ add_new_dependencies(receiver_class, dependencies, method_name)
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ def extract_param_classes(method_args, params)
51
+ dependencies = []
52
+ params.each do |param|
53
+ if param.class == Symbol
54
+ type = method_args[param]
55
+ type = type.to_a
56
+ dependencies << type
57
+ elsif param.class == String
58
+ type = [param]
59
+ dependencies << type
60
+ end
61
+ end
62
+ dependencies
63
+ end
64
+
65
+ def extract_formal_parameter(params)
66
+ formal_params = []
67
+ params.each do |param|
68
+ if param.class == Symbol
69
+ formal_params << param
70
+ end
71
+ end
72
+ formal_params
73
+ end
74
+
75
+ def add_new_dependencies(receiver_class, dependencies, method_name)
76
+ add_to_dependencies(receiver_class, dependencies)
77
+ add_to_method_definitions(receiver_class, dependencies, method_name)
78
+ end
79
+
80
+ def add_to_dependencies(receiver_class, dependencies)
81
+ dep_class = @dependencies[receiver_class]
82
+ if dep_class.nil?
83
+ @dependencies[receiver_class] = Set.new
84
+ dep_class = @dependencies[receiver_class]
85
+ end
86
+ # utilizamos o flatten pois aqui não importa a posição
87
+ # do parametro formal
88
+ dependencies.flatten.each do |dependency|
89
+ dep_class.add(dependency)
90
+ end
91
+ end
92
+
93
+ def add_to_method_definitions(receiver_class, dependencies, method_name)
94
+ method_definitions = @method_definitions[receiver_class]
95
+ if method_definitions
96
+ method_definitions.each do |method_definition|
97
+ if method_definition.method_name == method_name
98
+ add_new_params_dependency(method_definition, dependencies)
99
+ break
100
+ end
101
+ end
102
+ end
103
+ end
104
+
105
+ def add_new_params_dependency(method_definition, dependencies)
106
+ args = method_definition.args.keys
107
+ dependencies.each_with_index do |deps, i|
108
+ # aqui mantemos a ordem dos parametros formais
109
+ formal_parameter_name = method_definition.args[args[i]]
110
+ if formal_parameter_name
111
+ deps.each do |dep|
112
+ begin
113
+ formal_parameter_name.add(dep)
114
+ rescue
115
+ binding.pry
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
121
+
122
+ end
123
+
124
+ end
125
+ end
126
+ end
@@ -1,3 +1,3 @@
1
1
  module Archruby
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.0"
3
3
  end
@@ -3,7 +3,8 @@ require 'spec_helper'
3
3
  describe Archruby::Architecture::FileContent do
4
4
 
5
5
  it 'get the content from the right files' do
6
- file_reader = Archruby::Architecture::FileContent.new("/Users/sergiomiranda/Labs/ruby_arch_checker/arch_checker/spec/dummy_app/app/")
6
+ fake_app_path = File.expand_path('../../dummy_app/app', __FILE__)
7
+ file_reader = Archruby::Architecture::FileContent.new(fake_app_path)
7
8
  content = file_reader.all_content_from_directory "controllers/**/*.rb"
8
9
  content.keys.should include('application_controller')
9
10
  content['application_controller'].should_not be_nil
@@ -21,8 +21,8 @@ describe Archruby::Architecture::ModuleDefinition do
21
21
  base_directory = File.expand_path('../../dummy_app/', __FILE__)
22
22
  config_definition = Archruby::Architecture::ConfigDefinition.new 'model', parsed_yaml['model']
23
23
  module_definition = Archruby::Architecture::ModuleDefinition.new(config_definition, base_directory)
24
- module_definition.already_has_dependency?("User", "ActiveRecord::Base").should be_true
25
- module_definition.already_has_dependency?("User", "ClassQualquer").should be_false
24
+ expect(module_definition.already_has_dependency?("User", "ActiveRecord::Base")).to be_true
25
+ expect(module_definition.already_has_dependency?("User", "ClassQualquer")).to be_false
26
26
  end
27
27
 
28
28
  it 'build the dependencies correctly' do
@@ -38,13 +38,13 @@ describe Archruby::Architecture::ModuleDefinition do
38
38
  base_directory = File.expand_path('../../dummy_app/', __FILE__)
39
39
  config_definition = Archruby::Architecture::ConfigDefinition.new 'model', parsed_yaml['model']
40
40
  module_definition = Archruby::Architecture::ModuleDefinition.new(config_definition, base_directory)
41
- module_definition.is_mine?("Teste").should be_true
42
- module_definition.is_mine?("User").should be_true
43
- module_definition.is_mine?("ActiveRecord").should be_false
44
- module_definition.is_mine?("QualquerCoisa").should be_false
45
- module_definition.is_mine?("::User").should be_true
46
- module_definition.is_mine?("::User::Nao::Sei").should be_false
47
- module_definition.is_mine?("Testando::VaiAcessar").should be_true
41
+ expect(module_definition.is_mine?("Teste")).to be_true
42
+ expect(module_definition.is_mine?("User")).to be_true
43
+ expect(module_definition.is_mine?("ActiveRecord")).to be_false
44
+ expect(module_definition.is_mine?("QualquerCoisa")).to be_false
45
+ expect(module_definition.is_mine?("::User")).to be_true
46
+ expect(module_definition.is_mine?("::User::Nao::Sei")).to be_false
47
+ expect(module_definition.is_mine?("Testando::VaiAcessar")).to be_true
48
48
 
49
49
  config_definition = Archruby::Architecture::ConfigDefinition.new 'actioncontroller', parsed_yaml['actioncontroller']
50
50
  module_definition = Archruby::Architecture::ModuleDefinition.new(config_definition, base_directory)