Class: Dcov::Analyzer

Inherits:
Object
  • Object
show all
Defined in:
lib/dcov/analyzer.rb

Overview

Main class

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options) ⇒ Analyzer

Grab the arguments from the DCov init script or another calling script and feed them to RDoc for parsing.



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
# File 'lib/dcov/analyzer.rb', line 105

def initialize(options)
  @options = options
  raise "No files to analyze!" if @options[:files] == [] || @options[:files] == nil
  
  # Setup the analyzed tokens array so we can keep track of which methods we've already
  # taken a look at...
  @analyzed_tokens = []
  
  r = RDoc::RDoc.new
  
  # Instantiate our little hacked Stats class...
  @stats = Dcov::Stats.new
  r.stats = @stats
  
  # Get our analyzers together...
  @analyzers = []
  find_analyzers
  
  # Setup any options we need here...
  Options.instance.parse(["--tab-width", 2], {})
        
  # We have to use #send because #parse_files is private
  parsed_structure = r.send(:parse_files, RDocOptionsMock.new(options[:files]))
  
  # Analyze it, Spiderman!
  analyze parsed_structure
  
  # Generate the report!
  generate
end

Instance Attribute Details

#classesObject

Returns the value of attribute classes.



100
101
102
# File 'lib/dcov/analyzer.rb', line 100

def classes
  @classes
end

#hierarchyObject

Returns the value of attribute hierarchy.



100
101
102
# File 'lib/dcov/analyzer.rb', line 100

def hierarchy
  @hierarchy
end

#methodsObject

Returns the value of attribute methods.



100
101
102
# File 'lib/dcov/analyzer.rb', line 100

def methods
  @methods
end

#modulesObject

Returns the value of attribute modules.



100
101
102
# File 'lib/dcov/analyzer.rb', line 100

def modules
  @modules
end

#statsObject

Returns the value of attribute stats.



100
101
102
# File 'lib/dcov/analyzer.rb', line 100

def stats
  @stats
end

Instance Method Details

#analyze(hierarchy) ⇒ Object

Method to initialize analysis of the code; passes structure off to the process method which actually processes the tokens.



139
140
141
142
143
144
# File 'lib/dcov/analyzer.rb', line 139

def analyze(hierarchy)
  @hierarchy = hierarchy
  process

  @stats.print   
end

#analyze_token(token, classifier, stats) ⇒ Object



235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
# File 'lib/dcov/analyzer.rb', line 235

def analyze_token(token, classifier, stats)
  context = AnalysisContext.new(token, (token.comment || ''), classifier, stats)
  
  @all_analysis.call(context) if @all_analysis
  
  case classifier
    when :method
      @method_analysis.call(context) if @method_analysis
    when :class
      @class_analysis.call(context) if @class_analysis
    when :module
      @module_analysis.call(context) if @module_analysis
  end
  
  context.token
end

#documentation_for_all(&block) ⇒ Object



231
232
233
# File 'lib/dcov/analyzer.rb', line 231

def documentation_for_all(&block)
  @all_analysis = block
end

#documentation_for_classes(&block) ⇒ Object



223
224
225
# File 'lib/dcov/analyzer.rb', line 223

def documentation_for_classes(&block)
  @class_analysis = block
end

#documentation_for_methods(&block) ⇒ Object



219
220
221
# File 'lib/dcov/analyzer.rb', line 219

def documentation_for_methods(&block)
  @method_analysis = block
end

#documentation_for_modules(&block) ⇒ Object



227
228
229
# File 'lib/dcov/analyzer.rb', line 227

def documentation_for_modules(&block)
  @module_analysis = block
end

#expose_to_analyzers(token) ⇒ Object

Fire off the token to each analyzer, letting it have its way with the token and the Stats instance.



207
208
209
210
211
212
213
214
215
216
217
# File 'lib/dcov/analyzer.rb', line 207

def expose_to_analyzers(token)
  @analyzers.each do |analyzer|
    classifier = token.classifier
    eval(File.read(analyzer))
    
    token = analyze_token(token, classifier, @stats)
    @method_analysis, @module_analysis, @class_analysis, @all_analysis = nil
  end
  
  token
end

#find_analyzersObject

Grok the analyzers directory and find all analyzers



198
199
200
201
202
203
# File 'lib/dcov/analyzer.rb', line 198

def find_analyzers
  Dir::entries(File.dirname(__FILE__) + "/analyzers").each do |analyzer|
    next unless /(\w+)_analyzer.rb$/ =~ analyzer
    @analyzers << File.dirname(__FILE__) + "/analyzers/#{analyzer}"
  end
end

#generateObject

Generate the output based on the format specified TODO: Have an argument sanity check at startup to make sure we actually have a generator for the format



178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/dcov/analyzer.rb', line 178

def generate
  print "Generating report..."
  require File.dirname(__FILE__) + "/generators/#{@options[:output_format]}/generator.rb"

  generator = Dcov::Generator.new @stats.renderable_data
  report = generator.to_s
  print "done.\n"
  
  print "Writing report..."
  if (!File.exists?("#{@options[:path]}/coverage.html")) || (File.writable?("#{@options[:path]}/coverage.html"))
    output_file = File.open("#{@options[:path]}/coverage.html", "w")
    output_file.write report
    output_file.close
    print "done.\n"
  else
    raise "Can't write to [#{@options[:path]}/coverage.html]."
  end
end

#param_names_for(token) ⇒ Object



252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
# File 'lib/dcov/analyzer.rb', line 252

def param_names_for(token)
  if token.params
    params = token.params.dup
    params.gsub!(/\(/, '')
    params.gsub!(/\)/, '')

    if params.include?(",")
      params = params.split(",")
    else
      params = [params]
    end

    processed_params = []

    params.each do |param|
      param_value = nil

      # We have a default value...
      if param.include?('=')
        param_pieces = param.scan(/(.*)=(.*)/)[0]
        param = param_pieces[0].strip 
        param_value = param_pieces[1].strip
      end

      processed_params << [param, param_value]
    end

    if processed_params == [["", nil]]
      []
    else
      processed_params  
    end
  else
    []
  end
end

#processObject

Method to start walking the hierarchy of tokens, separating them into covered/not covered (and eventually lexing their comments for quality).



149
150
151
152
153
154
155
156
157
158
159
# File 'lib/dcov/analyzer.rb', line 149

def process
  @hierarchy.each do |hier| 
    hier.classes.each do |cls| 
      process_token cls
    end
    
    hier.modules.each do |mod|
      process_token mod
    end
  end
end

#process_token(token) ⇒ Object

Method to process all the tokens for a token…recursion FTW! :)



162
163
164
165
166
167
168
169
170
171
172
173
174
# File 'lib/dcov/analyzer.rb', line 162

def process_token(token)
  analyzed_token = AnalyzedToken.new(token.name, token.parent)
  unless @analyzed_tokens.include?(analyzed_token)
    token = expose_to_analyzers(token)
    @analyzed_tokens << analyzed_token
             
    [:method_list, :classes, :modules].each do |meth, type|
      token.send(meth).each do |item|
        process_token item
      end if token.respond_to?(meth)
    end
  end
end