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.
- checksums.yaml +4 -4
- data/.travis.yml +3 -0
- data/README.md +1 -1
- data/Rakefile +46 -0
- data/TODO.rtf +20 -0
- data/architecture.yml +51 -0
- data/archruby.gemspec +3 -0
- data/bin/archruby +1 -0
- data/lib/archruby.rb +14 -2
- data/lib/archruby/architecture/architecture.rb +6 -6
- data/lib/archruby/architecture/config_definition.rb +13 -13
- data/lib/archruby/architecture/constraint_break.rb +1 -1
- data/lib/archruby/architecture/dependency.rb +3 -1
- data/lib/archruby/architecture/file_content.rb +2 -2
- data/lib/archruby/architecture/module_definition.rb +33 -20
- data/lib/archruby/architecture/parser.rb +25 -11
- data/lib/archruby/architecture/type_inference_checker.rb +29 -13
- data/lib/archruby/presenters/dsm.rb +163 -0
- data/lib/archruby/presenters/dsm/cell_dsm.rb +17 -0
- data/lib/archruby/presenters/dsm/dsm_css.css +77 -0
- data/lib/archruby/presenters/graph.rb +12 -9
- data/lib/archruby/ruby/parser.rb +131 -125
- data/lib/archruby/ruby/type_inference/dependency_organizer.rb +53 -0
- data/lib/archruby/ruby/type_inference/ruby/class_dependency.rb +22 -0
- data/lib/archruby/ruby/type_inference/ruby/internal_method_invocation.rb +20 -0
- data/lib/archruby/ruby/type_inference/ruby/method_definition.rb +20 -0
- data/lib/archruby/ruby/type_inference/ruby/parser_for_typeinference.rb +537 -0
- data/lib/archruby/ruby/type_inference/ruby/process_method_arguments.rb +155 -0
- data/lib/archruby/ruby/type_inference/ruby/process_method_body.rb +427 -0
- data/lib/archruby/ruby/type_inference/ruby/process_method_params.rb +276 -0
- data/lib/archruby/ruby/type_inference/type_inference_checker.rb +126 -0
- data/lib/archruby/version.rb +1 -1
- data/spec/architecture/file_content_spec.rb +2 -1
- data/spec/architecture/module_definition_spec.rb +9 -9
- data/spec/dummy_app/lib/teste_class.rb +6 -0
- data/spec/ruby/type_inference/dependency_organizer_spec.rb +20 -0
- data/spec/ruby/type_inference/fixtures/homebrew_bottles_class.rb +139 -0
- data/spec/ruby/type_inference/fixtures/homebrew_brew_teste.rb +1323 -0
- data/spec/ruby/type_inference/fixtures/rails_action_view_class_teste.rb +89 -0
- data/spec/ruby/type_inference/fixtures/rails_active_record_class.rb +99 -0
- data/spec/ruby/type_inference/fixtures/rails_teste_active_record.rb +55 -0
- data/spec/ruby/type_inference/fixtures/teste2.rb +16 -0
- data/spec/ruby/type_inference/fixtures/teste_class_and_args.rb +49 -0
- data/spec/ruby/type_inference/fixtures/teste_class_and_args2.rb +11 -0
- data/spec/ruby/type_inference/parser_for_typeinference_spec.rb +69 -0
- data/spec/ruby/type_inference/type_inference_checker_spec.rb +47 -0
- 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
|
data/lib/archruby/version.rb
CHANGED
@@ -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
|
-
|
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").
|
25
|
-
module_definition.already_has_dependency?("User", "ClassQualquer").
|
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").
|
42
|
-
module_definition.is_mine?("User").
|
43
|
-
module_definition.is_mine?("ActiveRecord").
|
44
|
-
module_definition.is_mine?("QualquerCoisa").
|
45
|
-
module_definition.is_mine?("::User").
|
46
|
-
module_definition.is_mine?("::User::Nao::Sei").
|
47
|
-
module_definition.is_mine?("Testando::VaiAcessar").
|
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)
|