Class: SelfFlagellation::Flagellate

Inherits:
SexpProcessor
  • Object
show all
Includes:
UnifiedRuby
Defined in:
lib/self-flagellation/flagellate.rb

Constant Summary collapse

THRESHOLD =
$a ? 1.0 : 0.60
SCORES =
Hash.new(1)
BRANCHING =
[ :and, :case, :else, :if, :or, :rescue, :until, :when, :while ]
OTHER_SCORES =

various non-call constructs

{
  :alias => 2,
  :assignment => 1,
  :block => 1,
  :branch => 1,
  :lit_fixnum => 0.25,
  :sclass => 5,
  :super => 1,
  :to_proc_icky! => 10,
  :to_proc_normal => 5,
  :yield => 1,
}
@@no_class =
:main
@@no_method =
:none

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize ⇒ Flagellate

Returns a new instance of Flagellate.



70
71
72
73
74
75
76
77
78
# File 'lib/self-flagellation/flagellate.rb', line 70

def initialize
  super
  @pt = ParseTree.new(false)
  @klasses = []
  @methods = []
  self.auto_shift_type = true
  self.require_empty = false # HACK
  self.reset
end

Instance Attribute Details

#calls ⇒ Object (readonly)

Returns the value of attribute calls.



68
69
70
# File 'lib/self-flagellation/flagellate.rb', line 68

def calls
  @calls
end

Instance Method Details

#add_to_score(name, score) ⇒ Object



91
92
93
# File 'lib/self-flagellation/flagellate.rb', line 91

def add_to_score(name, score)
  @calls["#{self.klass_name}##{self.method_name}"][name] += score * @multiplier
end

#bad_dog!(bonus) {|42| ... } ⇒ Object

Yields:

  • (42)


95
96
97
98
99
# File 'lib/self-flagellation/flagellate.rb', line 95

def bad_dog! bonus
  @multiplier += bonus
  yield 42
  @multiplier -= bonus
end

#bleed(exp) ⇒ Object



101
102
103
# File 'lib/self-flagellation/flagellate.rb', line 101

def bleed exp
  process exp.shift until exp.empty?
end

#flog_files(*files) ⇒ Object



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/self-flagellation/flagellate.rb', line 105

def flog_files *files
  files.flatten.each do |file|
    if File.directory? file then
      flog_files Dir["#{file}/**/*.rb"]
    else
      warn "** flogging #{file}" if $v
      ruby = file == "-" ? $stdin.read : File.read(file)
      begin
        sexp = @pt.parse_tree_for_string(ruby, file)
        process Sexp.from_array(sexp).first
      rescue SyntaxError => e
        if e.inspect =~ /<%|%>/ then
          warn e.inspect + " at " + e.backtrace.first(5).join(', ')
          warn "...stupid lemmings and their bad erb templates... skipping"
        else
          raise e
        end
      end
    end
  end
end

#klass(name) ⇒ Object



127
128
129
130
131
# File 'lib/self-flagellation/flagellate.rb', line 127

def klass name
  @klasses.unshift name
  yield
  @klasses.shift
end

#klass_name ⇒ Object



133
134
135
# File 'lib/self-flagellation/flagellate.rb', line 133

def klass_name
  @klasses.first || @@no_class
end

#method(name) ⇒ Object



137
138
139
140
141
# File 'lib/self-flagellation/flagellate.rb', line 137

def method name
  @methods.unshift name
  yield
  @methods.shift
end

#method_name ⇒ Object



143
144
145
# File 'lib/self-flagellation/flagellate.rb', line 143

def method_name
  @methods.first || @@no_method
end

#other_scores ⇒ Object



208
209
210
# File 'lib/self-flagellation/flagellate.rb', line 208

def other_scores
  @other_scores || OTHER_SCORES
end

#process_alias(exp) ⇒ Object

Process Methods:



219
220
221
222
223
224
# File 'lib/self-flagellation/flagellate.rb', line 219

def process_alias(exp)
  process exp.shift
  process exp.shift
  add_to_score :alias, other_scores[:alias]
  s()
end

#process_and(exp) ⇒ Object



226
227
228
229
230
231
232
233
# File 'lib/self-flagellation/flagellate.rb', line 226

def process_and(exp)
  add_to_score :branch, other_scores[:branch]
  bad_dog! 0.1 do
    process exp.shift # lhs
    process exp.shift # rhs
  end
  s()
end

#process_attrasgn(exp) ⇒ Object



235
236
237
238
239
240
241
# File 'lib/self-flagellation/flagellate.rb', line 235

def process_attrasgn(exp)
  add_to_score :assignment, other_scores[:assignment]
  process exp.shift # lhs
  exp.shift # name
  process exp.shift # rhs
  s()
end

#process_attrset(exp) ⇒ Object



243
244
245
246
247
# File 'lib/self-flagellation/flagellate.rb', line 243

def process_attrset(exp)
  add_to_score :assignment, other_scores[:assignment]
  raise exp.inspect
  s()
end

#process_block(exp) ⇒ Object



249
250
251
252
253
254
# File 'lib/self-flagellation/flagellate.rb', line 249

def process_block(exp)
  bad_dog! 0.1 do
    bleed exp
  end
  s()
end

#process_block_pass(exp) ⇒ Object

[:block_pass, [:lit, :blah], [:fcall, :foo]]



257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
# File 'lib/self-flagellation/flagellate.rb', line 257

def process_block_pass(exp)
  arg = exp.shift
  call = exp.shift

  add_to_score :block_pass, other_scores[:block]

  case arg.first
  when :lvar, :dvar, :ivar, :cvar, :self, :const, :nil then
    # do nothing
  when :lit, :call then
    add_to_score :to_proc_normal, other_scores[:to_proc_normal]
  when :iter, *BRANCHING then
    add_to_score :to_proc_icky!, other_scores[:to_proc_icky!]
  else
    raise({:block_pass => [arg, call]}.inspect)
  end

  process arg
  process call

  s()
end

#process_call(exp) ⇒ Object



280
281
282
283
284
285
286
287
288
289
290
291
292
293
# File 'lib/self-flagellation/flagellate.rb', line 280

def process_call(exp)
  bad_dog! 0.2 do
    recv = process exp.shift
  end
  name = exp.shift
  bad_dog! 0.2 do
    args = process exp.shift
  end

  score = scores[name]
  add_to_score name, score

  s()
end

#process_case(exp) ⇒ Object



295
296
297
298
299
300
301
302
# File 'lib/self-flagellation/flagellate.rb', line 295

def process_case(exp)
  add_to_score :branch, other_scores[:branch]
  process exp.shift # recv
  bad_dog! 0.1 do
    bleed exp
  end
  s()
end

#process_class(exp) ⇒ Object



304
305
306
307
308
309
310
311
312
# File 'lib/self-flagellation/flagellate.rb', line 304

def process_class(exp)
  self.klass exp.shift do
    bad_dog! 1.0 do
      supr = process exp.shift
    end
    bleed exp
  end
  s()
end

#process_dasgn_curr(exp) ⇒ Object



314
315
316
317
318
319
# File 'lib/self-flagellation/flagellate.rb', line 314

def process_dasgn_curr(exp)
  add_to_score :assignment, other_scores[:assignment]
  exp.shift # name
  process exp.shift # assigment, if any
  s()
end

#process_defn(exp) ⇒ Object



321
322
323
324
325
326
# File 'lib/self-flagellation/flagellate.rb', line 321

def process_defn(exp)
  self.method exp.shift do
    bleed exp
  end
  s()
end

#process_defs(exp) ⇒ Object



328
329
330
331
332
333
334
# File 'lib/self-flagellation/flagellate.rb', line 328

def process_defs(exp)
  process exp.shift
  self.method exp.shift do
    bleed exp
  end
  s()
end

#process_else(exp) ⇒ Object



336
337
338
339
340
341
342
# File 'lib/self-flagellation/flagellate.rb', line 336

def process_else(exp)
  add_to_score :branch, other_scores[:branch]
  bad_dog! 0.1 do
    bleed exp
  end
  s()
end

#process_iasgn(exp) ⇒ Object



344
345
346
347
348
349
# File 'lib/self-flagellation/flagellate.rb', line 344

def process_iasgn(exp)
  add_to_score :assignment, other_scores[:assignment]
  exp.shift # name
  process exp.shift # rhs
  s()
end

#process_if(exp) ⇒ Object



351
352
353
354
355
356
357
358
359
# File 'lib/self-flagellation/flagellate.rb', line 351

def process_if(exp)
  add_to_score :branch, other_scores[:branch]
  process exp.shift # cond
  bad_dog! 0.1 do
    process exp.shift # true
    process exp.shift # false
  end
  s()
end

#process_iter(exp) ⇒ Object



361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
# File 'lib/self-flagellation/flagellate.rb', line 361

def process_iter(exp)
  context = (self.context - [:class, :module, :scope])
  if context.uniq.sort_by {|s|s.to_s} == [:block, :iter] then
    recv = exp.first
    if recv[0] == :call and recv[1] == nil and recv.arglist[1] and [:lit, :str].include? recv.arglist[1][0] then
      msg = recv[2]
      submsg = recv.arglist[1][1]
      self.method submsg do
        self.klass msg do
          bleed exp
        end
      end
      return s()
    end
  end

  add_to_score :branch, other_scores[:branch]

  process exp.shift # no penalty for LHS

  bad_dog! 0.1 do
    bleed exp
  end

  s()
end

#process_lasgn(exp) ⇒ Object



388
389
390
391
392
393
# File 'lib/self-flagellation/flagellate.rb', line 388

def process_lasgn(exp)
  add_to_score :assignment, other_scores[:assignment]
  exp.shift # name
  process exp.shift # rhs
  s()
end

#process_lit(exp) ⇒ Object



395
396
397
398
399
400
401
402
403
404
405
406
407
408
# File 'lib/self-flagellation/flagellate.rb', line 395

def process_lit(exp)
  value = exp.shift
  case value
  when 0, -1 then
    # ignore those because they're used as array indicies instead of first/last
  when Integer then
    add_to_score :lit_fixnum, other_scores[:lit_fixnum]
  when Float, Symbol, Regexp, Range then
    # do nothing
  else
    raise value.inspect
  end
  s()
end

#process_masgn(exp) ⇒ Object



410
411
412
413
414
415
# File 'lib/self-flagellation/flagellate.rb', line 410

def process_masgn(exp)
  add_to_score :assignment, other_scores[:assignment]
  process exp.shift # lhs
  process exp.shift # rhs
  s()
end

#process_module(exp) ⇒ Object



417
418
419
420
421
422
# File 'lib/self-flagellation/flagellate.rb', line 417

def process_module(exp)
  self.klass exp.shift do
    bleed exp
  end
  s()
end

#process_or(exp) ⇒ Object



424
425
426
427
428
429
430
431
# File 'lib/self-flagellation/flagellate.rb', line 424

def process_or(exp)
  add_to_score :branch, other_scores[:branch]
  bad_dog! 0.1 do
    process exp.shift # lhs
    process exp.shift # rhs
  end
  s()
end

#process_rescue(exp) ⇒ Object



433
434
435
436
437
438
439
# File 'lib/self-flagellation/flagellate.rb', line 433

def process_rescue(exp)
  add_to_score :branch, other_scores[:branch]
  bad_dog! 0.1 do
    bleed exp
  end
  s()
end

#process_sclass(exp) ⇒ Object



441
442
443
444
445
446
447
448
449
# File 'lib/self-flagellation/flagellate.rb', line 441

def process_sclass(exp)
  bad_dog! 0.5 do
    recv = process exp.shift
    bleed exp
  end

  add_to_score :sclass, other_scores[:sclass]
  s()
end

#process_super(exp) ⇒ Object



451
452
453
454
455
# File 'lib/self-flagellation/flagellate.rb', line 451

def process_super(exp)
  add_to_score :super, other_scores[:super]
  bleed exp
  s()
end

#process_until(exp) ⇒ Object



457
458
459
460
461
462
463
464
465
# File 'lib/self-flagellation/flagellate.rb', line 457

def process_until(exp)
  add_to_score :branch, other_scores[:branch]
  bad_dog! 0.1 do
    process exp.shift # cond
    process exp.shift # body
  end
  exp.shift # pre/post
  s()
end

#process_when(exp) ⇒ Object



467
468
469
470
471
472
473
# File 'lib/self-flagellation/flagellate.rb', line 467

def process_when(exp)
  add_to_score :branch, other_scores[:branch]
  bad_dog! 0.1 do
    bleed exp
  end
  s()
end

#process_while(exp) ⇒ Object



475
476
477
478
479
480
481
482
483
# File 'lib/self-flagellation/flagellate.rb', line 475

def process_while(exp)
  add_to_score :branch, other_scores[:branch]
  bad_dog! 0.1 do
    process exp.shift # cond
    process exp.shift # body
  end
  exp.shift # pre/post
  s()
end

#process_yield(exp) ⇒ Object



485
486
487
488
489
# File 'lib/self-flagellation/flagellate.rb', line 485

def process_yield(exp)
  add_to_score :yield, other_scores[:yield]
  bleed exp
  s()
end

#report(io = $stdout) ⇒ Object



147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/self-flagellation/flagellate.rb', line 147

def report io = $stdout
  current = 0
  total_score = self.total
  max = total_score * THRESHOLD
  totals = self.totals

  if $s then
    io.puts total_score
    exit 0
  end

  io.puts "Total score = #{total_score}"
  io.puts

  @calls.sort_by { |k,v| -totals[k] }.each do |klass_method, calls|
    total = totals[klass_method]
    io.puts "%s: (%.1f)" % [klass_method, total]
    calls.sort_by { |k,v| -v }.each do |call, count|
      io.puts "  %6.1f: %s" % [count, call]
    end

    current += total
    break if current >= max
  end
ensure
  self.reset
end

#reset ⇒ Object



175
176
177
178
179
# File 'lib/self-flagellation/flagellate.rb', line 175

def reset
  @totals = @total_score = nil
  @multiplier = 1.0
  @calls = Hash.new { |h,k| h[k] = Hash.new 0 }
end

#reset_scores(path = nil) ⇒ Object



80
81
82
83
84
85
86
87
88
89
# File 'lib/self-flagellation/flagellate.rb', line 80

def reset_scores(path = nil)
  if path
    yaml = YAML.load_file(path)
    @other_scores = yaml['OTHER_SCORES']
    @scores = Hash.new(1)
    @scores.merge!(yaml['SCORES'])
  end
rescue
  nil
end

#scores ⇒ Object



212
213
214
# File 'lib/self-flagellation/flagellate.rb', line 212

def scores
  @scores || SCORES
end

#total ⇒ Object



181
182
183
184
185
# File 'lib/self-flagellation/flagellate.rb', line 181

def total
  self.totals unless @total_score # calculates total_score as well

  @total_score
end

#totals ⇒ Object



187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
# File 'lib/self-flagellation/flagellate.rb', line 187

def totals
  unless @totals then
    @total_score = 0
    @totals = Hash.new(0)
    self.calls.each do |meth, tally|
      a, b, c = 0, 0, 0
      tally.each do |cat, score|
        case cat
        when :assignment then a += score
        when :branch     then b += score
        else                  c += score
        end
      end
      score = Math.sqrt(a*a + b*b + c*c)
      @totals[meth] = score
      @total_score += score
    end
  end
  @totals
end