flog 2.4.0 → 2.5.0

Sign up to get free protection for your applications and to get access to all the features.
data.tar.gz.sig CHANGED
@@ -1 +1,2 @@
1
- |Du�c�I(h��$�7U�|V��
1
+ /2HH��0,4#PM�F�hN�jTՑ���=;�c���j��;��&34��3Q0�� ��5��>�ǏAW{t�f��bu��� N��=�Vw.�����6�䉅YNV�5�XDJ��з/E�}˗���h� R�ƳE�L�MMK� ���� ��
2
+ ��������ޏ�6N�y%71�y���TDjv���1��~�����P��U���0���i2"f���yp(�~mZ�j�q���.5����
@@ -1,3 +1,20 @@
1
+ === 2.5.0 / 2010-09-01
2
+
3
+ * 1 major enhancement:
4
+
5
+ * Added plugin system. Define a module under Flog to extend it.
6
+
7
+ * 3 minor enhancements:
8
+
9
+ * Added special case penalty for wtf to_proc: blah(&b = proc {...}) (benjaminb)
10
+ * Improved tests and test coverage.
11
+ * Unfactored & refactored report code. Much cleaner and more maintainable now.
12
+
13
+ * 2 bug fixes:
14
+
15
+ * Fixed API change for FlogTask (andreacampi)
16
+ * Fixed bad edgecase handler for block_pass (benjaminb)
17
+
1
18
  === 2.4.0 / 2009-12-15
2
19
 
3
20
  * 4 minor enhancements:
data/bin/flog CHANGED
@@ -3,6 +3,8 @@
3
3
  require 'optparse'
4
4
  require 'flog'
5
5
 
6
+ Flog.load_plugins
7
+
6
8
  options = Flog.parse_options ARGV
7
9
 
8
10
  ARGV << "-" if ARGV.empty?
@@ -4,7 +4,7 @@ require 'ruby_parser'
4
4
  require 'optparse'
5
5
 
6
6
  class Flog < SexpProcessor
7
- VERSION = '2.4.0'
7
+ VERSION = '2.5.0'
8
8
 
9
9
  THRESHOLD = 0.60
10
10
  SCORES = Hash.new 1
@@ -23,6 +23,7 @@ class Flog < SexpProcessor
23
23
  :sclass => 5,
24
24
  :super => 1,
25
25
  :to_proc_icky! => 10,
26
+ :to_proc_lasgn => 15,
26
27
  :to_proc_normal => 5,
27
28
  :yield => 1,
28
29
  }
@@ -72,6 +73,41 @@ class Flog < SexpProcessor
72
73
  attr_reader :calls, :option, :class_stack, :method_stack, :mass
73
74
  attr_reader :method_locations
74
75
 
76
+ def self.plugins
77
+ @plugins ||= {}
78
+ end
79
+
80
+ # TODO: I think I want to do this more like hoe's plugin system. Generalize?
81
+ def self.load_plugins
82
+ loaded, found = {}, {}
83
+
84
+ Gem.find_files("flog/*.rb").reverse.each do |path|
85
+ found[File.basename(path, ".rb").intern] = path
86
+ end
87
+
88
+ found.each do |name, plugin|
89
+ next if loaded[name]
90
+ begin
91
+ warn "loading #{plugin}" # if $DEBUG
92
+ loaded[name] = load plugin
93
+ rescue LoadError => e
94
+ warn "error loading #{plugin.inspect}: #{e.message}. skipping..."
95
+ end
96
+ end
97
+
98
+ self.plugins.merge loaded
99
+
100
+ names = Flog.constants.map {|s| s.to_s}.reject {|n| n =~ /^[A-Z_]+$/}
101
+
102
+ names.each do |name|
103
+ # next unless Hoe.plugins.include? name.downcase.intern
104
+ mod = Flog.const_get(name)
105
+ next if Class === mod
106
+ warn "extend #{mod}" if $DEBUG
107
+ # self.extend mod
108
+ end
109
+ end
110
+
75
111
  # REFACTOR: from flay
76
112
  def self.expand_dirs_to_files *dirs
77
113
  extensions = ['rb']
@@ -92,6 +128,8 @@ class Flog < SexpProcessor
92
128
  }
93
129
 
94
130
  OptionParser.new do |opts|
131
+ opts.separator "Standard options:"
132
+
95
133
  opts.on("-a", "--all", "Display all flog results, not top 60%.") do
96
134
  option[:all] = true
97
135
  end
@@ -138,6 +176,16 @@ class Flog < SexpProcessor
138
176
  opts.on("-v", "--verbose", "Display progress during processing.") do
139
177
  option[:verbose] = true
140
178
  end
179
+
180
+ next if self.plugins.empty?
181
+ opts.separator "Plugin options:"
182
+
183
+ extra = self.methods.grep(/parse_options/) - %w(parse_options)
184
+
185
+ extra.sort.each do |msg|
186
+ self.send msg, opts, option
187
+ end
188
+
141
189
  end.parse! Array(args)
142
190
 
143
191
  option
@@ -160,6 +208,23 @@ class Flog < SexpProcessor
160
208
  total / calls.size
161
209
  end
162
210
 
211
+ ##
212
+ # Iterate over the calls sorted (descending) by score.
213
+
214
+ def each_by_score max = nil
215
+ my_totals = totals
216
+ current = 0
217
+
218
+ calls.sort_by { |k,v| -my_totals[k] }.each do |class_method, call_list|
219
+ score = my_totals[class_method]
220
+
221
+ yield class_method, score, call_list
222
+
223
+ current += score
224
+ break if max and current >= max
225
+ end
226
+ end
227
+
163
228
  ##
164
229
  # Flog the given files or directories. Smart. Deals with "-", syntax
165
230
  # errors, and traversing subdirectories intelligently.
@@ -257,67 +322,46 @@ class Flog < SexpProcessor
257
322
  ##
258
323
  # Output the report up to a given max or report everything, if nil.
259
324
 
260
- def output_details(io, max = nil)
261
- my_totals = totals
262
- current = 0
325
+ def output_details io, max = nil
326
+ io.puts
263
327
 
264
- if option[:group] then
265
- scores = Hash.new 0
266
- methods = Hash.new { |h,k| h[k] = [] }
267
-
268
- calls.sort_by { |k,v| -my_totals[k] }.each do |class_method, call_list|
269
- klass = class_method.split(/#/).first
270
- score = totals[class_method]
271
- methods[klass] << [class_method, score]
272
- scores[klass] += score
273
- current += score
274
- break if max and current >= max
275
- end
328
+ each_by_score max do |class_method, score, call_list|
329
+ return 0 if option[:methods] and class_method =~ /##{@@no_method}/
330
+ self.print_score io, class_method, score
276
331
 
277
- scores.sort_by { |_, n| -n }.each do |klass, total|
278
- io.puts
279
- io.puts "%8.1f: %s" % [total, "#{klass} total"]
280
- methods[klass].each do |name, score|
281
- location = @method_locations[name]
282
- if location then
283
- io.puts "%8.1f: %-32s %s" % [score, name, location]
284
- else
285
- io.puts "%8.1f: %s" % [score, name]
286
- end
332
+ if option[:details] then
333
+ call_list.sort_by { |k,v| -v }.each do |call, count|
334
+ io.puts " %6.1f: %s" % [count, call]
287
335
  end
288
- end
289
- else
290
- io.puts
291
- calls.sort_by { |k,v| -my_totals[k] }.each do |class_method, call_list|
292
- current += output_method_details(io, class_method, call_list)
293
- break if max and current >= max
336
+ io.puts
294
337
  end
295
338
  end
339
+ # io.puts
296
340
  end
297
341
 
298
342
  ##
299
- # Output the details for a method
343
+ # Output the report, grouped by class/module, up to a given max or
344
+ # report everything, if nil.
300
345
 
301
- def output_method_details(io, class_method, call_list)
302
- return 0 if option[:methods] and class_method =~ /##{@@no_method}/
346
+ def output_details_grouped io, max = nil
347
+ scores = Hash.new 0
348
+ methods = Hash.new { |h,k| h[k] = [] }
303
349
 
304
- total = totals[class_method]
350
+ each_by_score max do |class_method, score, call_list|
351
+ klass = class_method.split(/#|::/).first
305
352
 
306
- location = @method_locations[class_method]
307
- if location then # REFACTOR
308
- io.puts "%8.1f: %-32s %s" % [total, class_method, location]
309
- else
310
- io.puts "%8.1f: %s" % [total, class_method]
353
+ methods[klass] << [class_method, score]
354
+ scores[klass] += score
311
355
  end
312
356
 
313
- if option[:details] then
314
- call_list.sort_by { |k,v| -v }.each do |call, count|
315
- io.puts " %6.1f: %s" % [count, call]
316
- end
357
+ scores.sort_by { |_, n| -n }.each do |klass, total|
317
358
  io.puts
318
- end
319
359
 
320
- total
360
+ io.puts "%8.1f: %s" % [total, "#{klass} total"]
361
+ methods[klass].each do |name, score|
362
+ self.print_score io, name, score
363
+ end
364
+ end
321
365
  end
322
366
 
323
367
  ##
@@ -332,6 +376,18 @@ class Flog < SexpProcessor
332
376
  @multiplier -= bonus
333
377
  end
334
378
 
379
+ ##
380
+ # Print out one formatted score.
381
+
382
+ def print_score io, name, score
383
+ location = @method_locations[name]
384
+ if location then
385
+ io.puts "%8.1f: %-32s %s" % [score, name, location]
386
+ else
387
+ io.puts "%8.1f: %s" % [score, name]
388
+ end
389
+ end
390
+
335
391
  ##
336
392
  # Process each element of #exp in turn.
337
393
 
@@ -348,10 +404,11 @@ class Flog < SexpProcessor
348
404
 
349
405
  return if option[:score]
350
406
 
351
- if option[:all] then
352
- output_details(io)
407
+ max = option[:all] ? nil : total * THRESHOLD
408
+ if option[:group] then
409
+ output_details_grouped io, max
353
410
  else
354
- output_details(io, total * THRESHOLD)
411
+ output_details io, max
355
412
  end
356
413
  ensure
357
414
  self.reset
@@ -456,10 +513,12 @@ class Flog < SexpProcessor
456
513
  # do nothing
457
514
  when :lit, :call then
458
515
  add_to_score :to_proc_normal
516
+ when :lasgn then # blah(&l = proc { ... })
517
+ add_to_score :to_proc_lasgn
459
518
  when :iter, :dsym, :dstr, *BRANCHING then
460
519
  add_to_score :to_proc_icky!
461
520
  else
462
- raise({:block_pass_even_ickier! => [arg, call]}.inspect)
521
+ raise({:block_pass_even_ickier! => arg}.inspect)
463
522
  end
464
523
 
465
524
  process arg
@@ -583,7 +642,8 @@ class Flog < SexpProcessor
583
642
  value = exp.shift
584
643
  case value
585
644
  when 0, -1 then
586
- # ignore those because they're used as array indicies instead of first/last
645
+ # ignore those because they're used as array indicies instead of
646
+ # first/last
587
647
  when Integer then
588
648
  add_to_score :lit_fixnum
589
649
  when Float, Symbol, Regexp, Range then
@@ -21,7 +21,7 @@ class FlogTask < Rake::TaskLib
21
21
  desc "Analyze for code complexity in: #{dirs.join(', ')}"
22
22
  task name do
23
23
  flog = Flog.new
24
- flog.flog_files(*dirs)
24
+ flog.flog(*dirs)
25
25
  flog.report if verbose
26
26
 
27
27
  raise "Flog total too high! #{flog.total} > #{threshold}" if
@@ -106,7 +106,7 @@ class TestFlog < MiniTest::Unit::TestCase
106
106
  assert_equal exp, @flog.calls
107
107
 
108
108
  assert_equal 1.6, @flog.total unless @flog.option[:methods]
109
- assert_equal 4, @flog.mass["-"]
109
+ assert_equal 4, @flog.mass["-"] # HACK: 3 is for an unpublished sexp fmt
110
110
  ensure
111
111
  $stdin = old_stdin
112
112
  end
@@ -181,56 +181,46 @@ class TestFlog < MiniTest::Unit::TestCase
181
181
  end
182
182
 
183
183
  def test_output_details
184
+ @flog.option[:all] = true
184
185
  test_flog
185
186
 
186
- o = StringIO.new
187
- @flog.output_details o
188
-
189
- assert_equal "\n 1.6: main#none\n", o.string
190
- end
191
-
192
- def test_output_details_group
193
- @flog.option[:group] = true
194
-
195
- test_flog
187
+ @flog.totals["main#something"] = 42.0
196
188
 
197
189
  o = StringIO.new
198
190
  @flog.output_details o
199
191
 
200
- expected = "\n 1.6: main total\n 1.6: main#none\n"
192
+ expected = "\n 1.6: main#none\n"
201
193
 
202
194
  assert_equal expected, o.string
195
+ assert_equal 1.6, @flog.totals["main#none"]
203
196
  end
204
197
 
205
- def test_output_method_details
198
+ def test_output_details_grouped
206
199
  test_flog
207
200
 
208
- @flog.totals["main#something"] = 42.0
209
-
210
201
  o = StringIO.new
211
- n = @flog.output_method_details o, "main#none", @flog.calls["main#none"]
202
+ @flog.output_details_grouped o
212
203
 
213
- expected = " 1.6: main#none\n"
204
+ expected = "\n 1.6: main total\n 1.6: main#none\n"
214
205
 
215
206
  assert_equal expected, o.string
216
- assert_equal 1.6, n
217
207
  end
218
208
 
219
- def test_output_method_details_methods
209
+ def test_output_details_methods
220
210
  @flog.option[:methods] = true
221
211
 
222
212
  test_flog
223
213
 
224
- @flog.totals["main#something"] = 42.0
214
+ @flog.totals["main#something"] = 42.0 # TODO: no sense... why no output?
225
215
 
226
216
  o = StringIO.new
227
- n = @flog.output_method_details o, "main#none", @flog.calls["main#none"]
217
+ @flog.output_details o
228
218
 
229
- assert_equal "", o.string
230
- assert_equal 0, n
219
+ # HACK assert_equal "", o.string
220
+ assert_equal 0, @flog.totals["main#none"]
231
221
  end
232
222
 
233
- def test_output_method_details_detailed
223
+ def test_output_details_detailed
234
224
  @flog.option[:details] = true
235
225
 
236
226
  test_flog
@@ -238,16 +228,16 @@ class TestFlog < MiniTest::Unit::TestCase
238
228
  @flog.totals["main#something"] = 42.0
239
229
 
240
230
  o = StringIO.new
241
- n = @flog.output_method_details o, "main#none", @flog.calls["main#none"]
231
+ @flog.output_details o, nil
242
232
 
243
- expected = " 1.6: main#none
233
+ expected = "\n 1.6: main#none
244
234
  1.0: +
245
235
  0.6: lit_fixnum
246
236
 
247
237
  "
248
238
 
249
239
  assert_equal expected, o.string
250
- assert_equal 1.6, n
240
+ assert_equal 1.6, @flog.totals["main#none"]
251
241
  end
252
242
 
253
243
  # def test_process_until_empty
@@ -315,6 +305,33 @@ class TestFlog < MiniTest::Unit::TestCase
315
305
  :to_proc_normal => 6.0)
316
306
  end
317
307
 
308
+ def test_process_block_pass_iter
309
+ sexp = s(:block_pass,
310
+ s(:iter, s(:call, nil, :lambda, s(:arglist)), nil, s(:lit, 1)))
311
+
312
+ util_process(sexp, 12.316,
313
+ :lit_fixnum => 0.275,
314
+ :block_pass => 1.0,
315
+ :lambda => 1.0,
316
+ :branch => 1.0,
317
+ :to_proc_icky! => 10.0)
318
+ end
319
+
320
+ def test_process_block_pass_lasgn
321
+ sexp = s(:block_pass,
322
+ s(:lasgn,
323
+ :b,
324
+ s(:iter, s(:call, nil, :lambda, s(:arglist)), nil, s(:lit, 1))))
325
+
326
+ util_process(sexp, 17.333,
327
+ :lit_fixnum => 0.275,
328
+ :block_pass => 1.0,
329
+ :lambda => 1.0,
330
+ :assignment => 1.0,
331
+ :branch => 1.0,
332
+ :to_proc_lasgn => 15.0)
333
+ end
334
+
318
335
  def test_process_call
319
336
  sexp = s(:call, nil, :a, s(:arglist))
320
337
  util_process sexp, 1.0, :a => 1.0
@@ -485,14 +502,6 @@ class TestFlog < MiniTest::Unit::TestCase
485
502
  util_process sexp, 1.25, :super => 1.0, :lit_fixnum => 0.25
486
503
  end
487
504
 
488
- def test_process_super
489
- sexp = s(:super)
490
- util_process sexp, 1.00, :super => 1.0
491
-
492
- sexp = s(:super, s(:lit, 42))
493
- util_process sexp, 1.25, :super => 1.0, :lit_fixnum => 0.25
494
- end
495
-
496
505
  def test_process_while
497
506
  sexp = s(:while,
498
507
  s(:call, nil, :a, s(:arglist)),
@@ -529,10 +538,53 @@ class TestFlog < MiniTest::Unit::TestCase
529
538
  end
530
539
 
531
540
  def test_report_all
541
+ old_stdin = $stdin
542
+ $stdin = StringIO.new "2 + 3"
543
+ $stdin.rewind
544
+
545
+ @flog.flog "-"
546
+ @flog.totals["main#something"] = 42.0
547
+
548
+ exp = { "main#none" => { :+ => 1.0, :lit_fixnum => 0.6 } }
549
+ assert_equal exp, @flog.calls
550
+
532
551
  @flog.option[:all] = true
533
552
 
534
- test_report
553
+ assert_equal 1.6, @flog.total unless @flog.option[:methods]
554
+ assert_equal 4, @flog.mass["-"] # HACK: 3 is for an unpublished sexp fmt
555
+
556
+ o = StringIO.new
557
+ @flog.report o
558
+
559
+ expected = " 1.6: flog total
560
+ 1.6: flog/method average
561
+
562
+ 1.6: main#none
563
+ "
564
+
565
+ assert_equal expected, o.string
535
566
  # FIX: add thresholded output
567
+ ensure
568
+ $stdin = old_stdin
569
+ end
570
+
571
+ def test_report_group
572
+ # TODO: add second group to ensure proper output
573
+ @flog.option[:group] = true
574
+
575
+ test_flog
576
+
577
+ o = StringIO.new
578
+ @flog.report o
579
+
580
+ expected = " 1.6: flog total
581
+ 1.6: flog/method average
582
+
583
+ 1.6: main total
584
+ 1.6: main#none
585
+ "
586
+
587
+ assert_equal expected, o.string
536
588
  end
537
589
 
538
590
  def test_score_method
metadata CHANGED
@@ -1,7 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flog
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.4.0
4
+ hash: 27
5
+ prerelease: false
6
+ segments:
7
+ - 2
8
+ - 5
9
+ - 0
10
+ version: 2.5.0
5
11
  platform: ruby
6
12
  authors:
7
13
  - Ryan Davis
@@ -30,39 +36,87 @@ cert_chain:
30
36
  FBHgymkyj/AOSqKRIpXPhjC6
31
37
  -----END CERTIFICATE-----
32
38
 
33
- date: 2009-12-15 00:00:00 -08:00
39
+ date: 2010-09-01 00:00:00 -07:00
34
40
  default_executable:
35
41
  dependencies:
36
42
  - !ruby/object:Gem::Dependency
37
43
  name: sexp_processor
38
- type: :runtime
39
- version_requirement:
40
- version_requirements: !ruby/object:Gem::Requirement
44
+ prerelease: false
45
+ requirement: &id001 !ruby/object:Gem::Requirement
46
+ none: false
41
47
  requirements:
42
48
  - - ~>
43
49
  - !ruby/object:Gem::Version
50
+ hash: 7
51
+ segments:
52
+ - 3
53
+ - 0
44
54
  version: "3.0"
45
- version:
55
+ type: :runtime
56
+ version_requirements: *id001
46
57
  - !ruby/object:Gem::Dependency
47
58
  name: ruby_parser
48
- type: :runtime
49
- version_requirement:
50
- version_requirements: !ruby/object:Gem::Requirement
59
+ prerelease: false
60
+ requirement: &id002 !ruby/object:Gem::Requirement
61
+ none: false
51
62
  requirements:
52
63
  - - ~>
53
64
  - !ruby/object:Gem::Version
65
+ hash: 3
66
+ segments:
67
+ - 2
68
+ - 0
54
69
  version: "2.0"
55
- version:
70
+ type: :runtime
71
+ version_requirements: *id002
56
72
  - !ruby/object:Gem::Dependency
57
- name: hoe
73
+ name: rubyforge
74
+ prerelease: false
75
+ requirement: &id003 !ruby/object:Gem::Requirement
76
+ none: false
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ hash: 7
81
+ segments:
82
+ - 2
83
+ - 0
84
+ - 4
85
+ version: 2.0.4
58
86
  type: :development
59
- version_requirement:
60
- version_requirements: !ruby/object:Gem::Requirement
87
+ version_requirements: *id003
88
+ - !ruby/object:Gem::Dependency
89
+ name: minitest
90
+ prerelease: false
91
+ requirement: &id004 !ruby/object:Gem::Requirement
92
+ none: false
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ hash: 9
97
+ segments:
98
+ - 1
99
+ - 7
100
+ - 1
101
+ version: 1.7.1
102
+ type: :development
103
+ version_requirements: *id004
104
+ - !ruby/object:Gem::Dependency
105
+ name: hoe
106
+ prerelease: false
107
+ requirement: &id005 !ruby/object:Gem::Requirement
108
+ none: false
61
109
  requirements:
62
110
  - - ">="
63
111
  - !ruby/object:Gem::Version
64
- version: 2.4.0
65
- version:
112
+ hash: 19
113
+ segments:
114
+ - 2
115
+ - 6
116
+ - 2
117
+ version: 2.6.2
118
+ type: :development
119
+ version_requirements: *id005
66
120
  description: |-
67
121
  Flog reports the most tortured code in an easy to read pain
68
122
  report. The higher the score, the more pain the code is in.
@@ -98,21 +152,27 @@ rdoc_options:
98
152
  require_paths:
99
153
  - lib
100
154
  required_ruby_version: !ruby/object:Gem::Requirement
155
+ none: false
101
156
  requirements:
102
157
  - - ">="
103
158
  - !ruby/object:Gem::Version
159
+ hash: 3
160
+ segments:
161
+ - 0
104
162
  version: "0"
105
- version:
106
163
  required_rubygems_version: !ruby/object:Gem::Requirement
164
+ none: false
107
165
  requirements:
108
166
  - - ">="
109
167
  - !ruby/object:Gem::Version
168
+ hash: 3
169
+ segments:
170
+ - 0
110
171
  version: "0"
111
- version:
112
172
  requirements: []
113
173
 
114
174
  rubyforge_project: seattlerb
115
- rubygems_version: 1.3.5
175
+ rubygems_version: 1.3.7
116
176
  signing_key:
117
177
  specification_version: 3
118
178
  summary: Flog reports the most tortured code in an easy to read pain report
metadata.gz.sig CHANGED
Binary file