Class: Archruby::Architecture::ModuleDefinition

Inherits:
Object
  • Object
show all
Defined in:
lib/archruby/architecture/module_definition.rb

Constant Summary collapse

ALLOWED_CONSTRAINTS =
%w(required allowed forbidden)

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config_definition, base_directory) ⇒ ModuleDefinition

Returns a new instance of ModuleDefinition.



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/archruby/architecture/module_definition.rb', line 15

def initialize(config_definition, base_directory)
  @config_definition = config_definition
  @name = @config_definition.module_name
  @allowed_modules = @config_definition.allowed_modules
  @required_modules = @config_definition.required_modules
  @forbidden_modules = @config_definition.forbidden_modules
  @base_directory = base_directory
  @files_and_contents = []
  @classes = []
  @dependencies = []
  @classes_and_dependencies = []
  @class_methods_and_deps = []
  @class_methods_calls = []
  @type_inference_dependencies = []
  @type_inference_methods_calls =[]
  extract_content_of_files
  extract_dependencies
  #break type = TypeInferenceChecker.new
end

Instance Attribute Details

#allowed_modulesObject (readonly)

Returns the value of attribute allowed_modules.



8
9
10
# File 'lib/archruby/architecture/module_definition.rb', line 8

def allowed_modules
  @allowed_modules
end

#class_methods_and_depsObject (readonly)

Returns the value of attribute class_methods_and_deps.



8
9
10
# File 'lib/archruby/architecture/module_definition.rb', line 8

def class_methods_and_deps
  @class_methods_and_deps
end

#class_methods_callsObject (readonly)

Returns the value of attribute class_methods_calls.



8
9
10
# File 'lib/archruby/architecture/module_definition.rb', line 8

def class_methods_calls
  @class_methods_calls
end

#classesObject

Returns the value of attribute classes.



13
14
15
# File 'lib/archruby/architecture/module_definition.rb', line 13

def classes
  @classes
end

#classes_and_dependenciesObject (readonly)

Returns the value of attribute classes_and_dependencies.



8
9
10
# File 'lib/archruby/architecture/module_definition.rb', line 8

def classes_and_dependencies
  @classes_and_dependencies
end

#dependenciesObject (readonly)

Returns the value of attribute dependencies.



8
9
10
# File 'lib/archruby/architecture/module_definition.rb', line 8

def dependencies
  @dependencies
end

#forbidden_modulesObject (readonly)

Returns the value of attribute forbidden_modules.



8
9
10
# File 'lib/archruby/architecture/module_definition.rb', line 8

def forbidden_modules
  @forbidden_modules
end

#nameObject (readonly)

Returns the value of attribute name.



8
9
10
# File 'lib/archruby/architecture/module_definition.rb', line 8

def name
  @name
end

#required_modulesObject (readonly)

Returns the value of attribute required_modules.



8
9
10
# File 'lib/archruby/architecture/module_definition.rb', line 8

def required_modules
  @required_modules
end

#type_inference_dependenciesObject (readonly)

Returns the value of attribute type_inference_dependencies.



8
9
10
# File 'lib/archruby/architecture/module_definition.rb', line 8

def type_inference_dependencies
  @type_inference_dependencies
end

#type_inference_methods_callsObject (readonly)

Returns the value of attribute type_inference_methods_calls.



8
9
10
# File 'lib/archruby/architecture/module_definition.rb', line 8

def type_inference_methods_calls
  @type_inference_methods_calls
end

Instance Method Details

#add_new_dep(class_name, type_inference_dep) ⇒ Object



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/archruby/architecture/module_definition.rb', line 67

def add_new_dep(class_name, type_inference_dep)
  if !type_inference_dep.nil? && !already_has_dependency?(class_name, type_inference_dep)
    new_dep = Archruby::Architecture::Dependency.new(type_inference_dep, nil)
    @dependencies << type_inference_dep
    @classes_and_dependencies.each do |class_and_dep|
      if class_and_dep.keys.first.eql?(class_name)
        class_and_dep[class_and_dep.keys.first].push(new_dep)
      end
    end
  end
  # aqui precisamos tomar cuidado quando a classe ainda não está na estrutura
  # classes and dependencies (tem exemplo disso no findmeontwitter)
  # precisamos verificar se a dependencia foi adicionada, e caso não tenha sido
  # devemos adicionar ao final do loop
end

#already_has_dependency?(class_name, class_dep) ⇒ Boolean

Returns:

  • (Boolean)


83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/archruby/architecture/module_definition.rb', line 83

def already_has_dependency?(class_name, class_dep)
  has_dep = false
  @classes_and_dependencies.each do |class_and_dep|
    if class_and_dep.keys.first.eql?(class_name)
      class_and_dep[class_and_dep.keys.first].each do |dependency|
        if dependency.class_name.eql?(class_dep)
          has_dep = true
          break
        end
      end
    end
  end
  has_dep
end

#extract_content_of_files(file_extractor = Archruby::Architecture::FileContent) ⇒ Object



35
36
37
38
39
40
41
42
# File 'lib/archruby/architecture/module_definition.rb', line 35

def extract_content_of_files(file_extractor = Archruby::Architecture::FileContent)
  return if !@classes.empty?
  file_extractor = file_extractor.new(@base_directory)
  @config_definition.files.each do |file|
    file_content = file_extractor.all_content_from_directory(file)
    @files_and_contents << file_content
  end
end

#extract_dependencies(ruby_parser = Archruby::Ruby::Parser) ⇒ Object



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/archruby/architecture/module_definition.rb', line 44

def extract_dependencies(ruby_parser = Archruby::Ruby::Parser)
  return if !@classes.empty?
  @files_and_contents.each do |file_and_content|
    file_and_content.each do |file_name, content|
      parser = ruby_parser.new content
      @classes << parser.classes
      @dependencies << parser.dependencies
      @classes_and_dependencies << parser.classes_and_dependencies
      @class_methods_and_deps << parser.type_inference
      @class_methods_calls << parser.method_calls
      @type_inference_dependencies << parser.type_propagation_parser.dependencies
      @type_inference_methods_calls << parser.type_propagation_parser.method_definitions
    end
  end
  @classes << @config_definition.gems
  @classes.flatten!
  @dependencies.flatten!
  @class_methods_and_deps.flatten!
  @class_methods_calls.flatten!
  @type_inference_dependencies.flatten!
  @type_inference_methods_calls.flatten!
end

#is_empty?Boolean

Returns:

  • (Boolean)


162
163
164
# File 'lib/archruby/architecture/module_definition.rb', line 162

def is_empty?
  @classes.empty?
end

#is_external?Boolean

Returns:

  • (Boolean)


158
159
160
# File 'lib/archruby/architecture/module_definition.rb', line 158

def is_external?
  !@config_definition.gems.empty?
end

#is_mine?(class_name) ⇒ Boolean

Returns:

  • (Boolean)


98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# File 'lib/archruby/architecture/module_definition.rb', line 98

def is_mine?(class_name)
  #binding.pry
  splited_class_name = class_name.split('::')
  first_class_name = splited_class_name.first
  is_mine = false
  if first_class_name.empty?
    #pocurando por um match exato de dependencia
    first_name = splited_class_name[1]
    splited_class_name.shift # retirando o elemento ''
    class_name = splited_class_name.join("::")
    @classes.each do |klass|
      #TODO Arrumar isso com uma expressao regular
      if klass.include?(class_name) && klass.size == class_name.size
        is_mine = true
        break
      end
    end
    if !is_mine && !@config_definition.gems.empty?
      @classes.each do |klass|
        #TODO Arrumar isso com uma expressao regular
        if klass.include?(first_name) && klass.size == first_name.size
          is_mine = true
          break
        end
      end
    end
  end
  if !is_mine
    # procurando por acesso a classe que possa ser desse modulo
    class_name = splited_class_name.join("::")
    included_separator = class_name.include?("::")
    @classes.each do |klass|
      #TODO Arrumar isso com uma expressao regular
      if included_separator
        if klass.include?(class_name)
          is_mine = true
          break
        end
      else
        if klass.include?(class_name) && klass.size == class_name.size
          is_mine = true
          break
        end
      end
    end
  end
  if !is_mine
    # procurando por GEM
    @classes.each do |klass|
      #TODO Arrumar isso com uma expressao regular
      if klass.include?(first_class_name) && klass.size == first_class_name.size
        is_mine = true
        break
      end
    end
  end

  return is_mine
end

#verify_allowed(architecture) ⇒ Object



238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
# File 'lib/archruby/architecture/module_definition.rb', line 238

def verify_allowed(architecture)
  return if @config_definition.allowed_modules.empty?
  breaks = []
  @classes_and_dependencies.each do |class_and_depencies|
    class_and_depencies.each do |class_name, dependencies|
      dependencies.each do |dependency|
        module_name = architecture.module_name(dependency.class_name)
        next if architecture.is_ruby_internals? module_name
        if module_name != self.name && !@config_definition.allowed_modules.include?(module_name)
          next if /[A-Z]_+[A-Z]/.match(dependency.class_name) || @config_definition.required_modules.include?(module_name)
          breaks << Archruby::Architecture::ConstraintBreak.new(
            :type => 'divergence',
            :class_origin => class_name,
            :line_origin => dependency.line_number,
            :class_target => dependency.class_name,
            :module_origin => self.name,
            :module_target => module_name,
            :msg => "module #{self.name} is not allowed to depend on module #{module_name}")
        end
      end
    end
  end
  breaks
end

#verify_constraints(architecture) ⇒ Object



166
167
168
169
170
171
172
173
# File 'lib/archruby/architecture/module_definition.rb', line 166

def verify_constraints(architecture)
  required_breaks = verify_required(architecture)
  forbidden_breaks = verify_forbidden(architecture)
  allowed_breaks = verify_allowed(architecture)
  all_constraints_breaks = [required_breaks, forbidden_breaks, allowed_breaks].flatten
  all_constraints_breaks.delete(nil)
  all_constraints_breaks
end

#verify_forbidden(architecture) ⇒ Object



213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
# File 'lib/archruby/architecture/module_definition.rb', line 213

def verify_forbidden(architecture)
  return if @config_definition.forbidden_modules.empty?
  breaks = []
  @classes_and_dependencies.each do |class_and_depencies|
    class_and_depencies.each do |class_name, dependencies|
      dependencies.each do |dependency|
        module_name = architecture.module_name(dependency.class_name)
        next if architecture.is_ruby_internals? module_name
        if @config_definition.forbidden_modules.include? module_name
          next if /[A-Z]_+[A-Z]/.match(dependency.class_name)
          breaks << Archruby::Architecture::ConstraintBreak.new(
            :type => 'divergence',
            :class_origin => class_name,
            :line_origin => dependency.line_number,
            :class_target => dependency.class_name,
            :module_origin => self.name,
            :module_target => module_name,
            :msg => "accessing a module which is forbidden")
        end
      end
    end
  end
  breaks
end

#verify_required(architecture) ⇒ Object

Verifica todas as classes do modulo Cada uma deve, de alguma forma, depender dos modulos que estao listados como required



177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
# File 'lib/archruby/architecture/module_definition.rb', line 177

def verify_required(architecture)
  return if @config_definition.required_modules.empty?
  breaks = []
  @classes_and_dependencies.each_with_index do |class_and_depencies, index|
    if class_and_depencies.empty?
      breaks << Archruby::Architecture::ConstraintBreak.new(
        :type => 'absence',
        :module_origin => self.name,
        :module_target => @config_definition.required_modules.first,
        :class_origin => @classes[index],
        :msg => "not implement a required module"
      )
      next
    end
    class_and_depencies.each do |class_name, dependencies|
      dependency_module_names = []
      dependencies.each do |dependency|
        module_name = architecture.module_name(dependency.class_name)
        dependency_module_names << module_name
      end
      @config_definition.required_modules.each do |required_module|
        if !dependency_module_names.include?(required_module)
          breaks << Archruby::Architecture::ConstraintBreak.new(
            :type => 'absence',
            :module_origin => self.name,
            :module_target => required_module,
            :class_origin => class_name,
            :msg => "not implement a required module"
          )
        end
      end
    end
  end
  breaks
end